diff --git a/qtribu/constants.py b/qtribu/constants.py
index 13c23ffa..42e0c03a 100644
--- a/qtribu/constants.py
+++ b/qtribu/constants.py
@@ -241,3 +241,4 @@ def local_path(self, base_path: Path = Path().home() / ".geotribu/cdn/") -> Path
QCHAT_MESSAGE_TYPE_LIKE = "like"
QCHAT_MESSAGE_TYPE_GEOJSON = "geojson"
QCHAT_MESSAGE_TYPE_CRS = "crs"
+QCHAT_MESSAGE_TYPE_BBOX = "bbox"
diff --git a/qtribu/gui/dck_qchat.py b/qtribu/gui/dck_qchat.py
index b246e165..5dfaed1d 100644
--- a/qtribu/gui/dck_qchat.py
+++ b/qtribu/gui/dck_qchat.py
@@ -31,6 +31,7 @@
CHEATCODE_IAMAROBOT,
CHEATCODE_QGIS_PRO_LICENSE,
CHEATCODES,
+ QCHAT_MESSAGE_TYPE_BBOX,
QCHAT_MESSAGE_TYPE_CRS,
QCHAT_MESSAGE_TYPE_GEOJSON,
QCHAT_MESSAGE_TYPE_IMAGE,
@@ -42,6 +43,7 @@
from qtribu.gui.qchat_tree_widget_items import (
MESSAGE_COLUMN,
QChatAdminTreeWidgetItem,
+ QChatBboxTreeWidgetItem,
QChatCrsTreeWidgetItem,
QChatGeojsonTreeWidgetItem,
QChatImageTreeWidgetItem,
@@ -49,6 +51,7 @@
)
from qtribu.logic.qchat_api_client import QChatApiClient
from qtribu.logic.qchat_messages import (
+ QChatBboxMessage,
QChatCrsMessage,
QChatExiterMessage,
QChatGeojsonMessage,
@@ -169,6 +172,7 @@ def __init__(
self.qchat_ws.like_message_received.connect(self.on_like_message_received)
self.qchat_ws.geojson_message_received.connect(self.on_geojson_message_received)
self.qchat_ws.crs_message_received.connect(self.on_crs_message_received)
+ self.qchat_ws.bbox_message_received.connect(self.on_bbox_message_received)
# send message signal listener
self.lne_message.returnPressed.connect(self.on_send_button_clicked)
@@ -190,7 +194,7 @@ def __init__(
)
# send extent message signal listener
- self.btn_send_extent.pressed.connect(self.on_send_extent_button_clicked)
+ self.btn_send_extent.pressed.connect(self.on_send_bbox_button_clicked)
self.btn_send_extent.setIcon(
QIcon(QgsApplication.iconPath("mActionViewExtentInCanvas.svg"))
)
@@ -576,6 +580,13 @@ def on_crs_message_received(self, message: QChatCrsMessage) -> None:
item = QChatCrsTreeWidgetItem(self.twg_chat, message)
self.add_tree_widget_item(item)
+ def on_bbox_message_received(self, message: QChatBboxMessage) -> None:
+ """
+ Launched when a BBOX message is received from the websocket
+ """
+ item = QChatBboxTreeWidgetItem(self.twg_chat, message, self.iface.mapCanvas())
+ self.add_tree_widget_item(item)
+
# endregion
def on_message_clicked(self, item: QTreeWidgetItem, column: int) -> None:
@@ -637,6 +648,15 @@ def on_custom_context_menu_requested(self, point: QPoint) -> None:
set_crs_action.triggered.connect(partial(item.on_click, MESSAGE_COLUMN))
menu.addAction(set_crs_action)
+ # if this is a bbox message
+ if type(item) is QChatBboxTreeWidgetItem:
+ set_bbox_action = QAction(
+ QgsApplication.getThemeIcon("mActionViewExtentInCanvas.svg"),
+ self.tr("Set current extent"),
+ )
+ set_bbox_action.triggered.connect(partial(item.on_click, MESSAGE_COLUMN))
+ menu.addAction(set_bbox_action)
+
# like message action if possible
if item.can_be_liked:
like_action = QAction(
@@ -799,13 +819,24 @@ def on_send_screenshot_button_clicked(self) -> None:
)
self.qchat_ws.send_message(message)
- def on_send_extent_button_clicked(self) -> None:
+ def on_send_bbox_button_clicked(self) -> None:
"""
Action called when the Send extent button is clicked
"""
- QMessageBox.critical(
- self, self.tr("Send extent"), self.tr("Not implemented yet")
+ crs = QgsProject.instance().crs()
+ rect = self.iface.mapCanvas().extent()
+ message = QChatBboxMessage(
+ type=QCHAT_MESSAGE_TYPE_BBOX,
+ author=self.settings.author_nickname,
+ avatar=self.settings.author_avatar,
+ crs_wkt=crs.toWkt(),
+ crs_authid=crs.authid(),
+ xmin=rect.xMinimum(),
+ xmax=rect.xMaximum(),
+ ymin=rect.yMinimum(),
+ ymax=rect.yMaximum(),
)
+ self.qchat_ws.send_message(message)
def on_send_crs_button_clicked(self) -> None:
"""
diff --git a/qtribu/gui/dck_qchat.ui b/qtribu/gui/dck_qchat.ui
index e62cdeeb..d60b4ffb 100644
--- a/qtribu/gui/dck_qchat.ui
+++ b/qtribu/gui/dck_qchat.ui
@@ -325,6 +325,9 @@
-
+
+ PointingHandCursor
+
Send Extent
@@ -332,6 +335,9 @@
-
+
+ PointingHandCursor
+
Send CRS
diff --git a/qtribu/gui/qchat_tree_widget_items.py b/qtribu/gui/qchat_tree_widget_items.py
index 57f2a0c4..f6973751 100644
--- a/qtribu/gui/qchat_tree_widget_items.py
+++ b/qtribu/gui/qchat_tree_widget_items.py
@@ -7,9 +7,13 @@
from qgis.core import (
QgsApplication,
QgsCoordinateReferenceSystem,
+ QgsCoordinateTransform,
+ QgsPointXY,
QgsProject,
+ QgsRectangle,
QgsVectorLayer,
)
+from qgis.gui import QgsMapCanvas
from qgis.PyQt.QtCore import QTime
from qgis.PyQt.QtGui import QBrush, QColor, QIcon, QPixmap
from qgis.PyQt.QtWidgets import (
@@ -22,6 +26,7 @@
from qtribu.constants import ADMIN_MESSAGES_AVATAR, ADMIN_MESSAGES_NICKNAME
from qtribu.logic.qchat_messages import (
+ QChatBboxMessage,
QChatCrsMessage,
QChatGeojsonMessage,
QChatImageMessage,
@@ -268,4 +273,49 @@ def can_be_copied_to_clipboard(self) -> bool:
return True
def copy_to_clipboard(self) -> None:
- QgsApplication.instance().clipboard().setText(json.dumps(self.message.crs_wkt))
+ QgsApplication.instance().clipboard().setText(self.message.crs_wkt)
+
+
+class QChatBboxTreeWidgetItem(QChatTreeWidgetItem):
+ def __init__(
+ self, parent: QTreeWidget, message: QChatBboxMessage, canvas: QgsMapCanvas
+ ):
+ super().__init__(parent, QTime.currentTime(), message.author, message.avatar)
+ self.message = message
+ self.canvas = canvas
+ self.init_time_and_author()
+ self.setText(MESSAGE_COLUMN, self.liked_message)
+ self.setToolTip(MESSAGE_COLUMN, self.liked_message)
+
+ # set foreground color if sent by user
+ if message.author == self.settings.author_nickname:
+ self.set_foreground_color(self.settings.qchat_color_self)
+
+ def on_click(self, column: int) -> None:
+ if column == MESSAGE_COLUMN:
+ # set current canvas extent to the received one
+ project = QgsProject.instance()
+ tr = QgsCoordinateTransform(
+ QgsCoordinateReferenceSystem(self.message.crs_wkt),
+ project.crs(),
+ project,
+ )
+ rect = QgsRectangle(
+ tr.transform(QgsPointXY(self.message.xmin, self.message.ymin)),
+ tr.transform(QgsPointXY(self.message.xmax, self.message.ymax)),
+ )
+ self.canvas.setExtent(rect)
+ self.canvas.refresh()
+
+ @property
+ def liked_message(self) -> str:
+ msg = f"[{self.message.xmin} {self.message.ymin}, {self.message.xmax} {self.message.ymax}]"
+ return f""
+
+ @property
+ def can_be_copied_to_clipboard(self) -> bool:
+ return True
+
+ def copy_to_clipboard(self) -> None:
+ msg = f"[{self.message.xmin} {self.message.ymin}, {self.message.xmax} {self.message.ymax}]"
+ QgsApplication.instance().clipboard().setText(msg)
diff --git a/qtribu/logic/qchat_messages.py b/qtribu/logic/qchat_messages.py
index 979dbafb..4dde0415 100644
--- a/qtribu/logic/qchat_messages.py
+++ b/qtribu/logic/qchat_messages.py
@@ -64,3 +64,15 @@ class QChatCrsMessage(QChatMessage):
avatar: Optional[str]
crs_wkt: str
crs_authid: str
+
+
+@dataclass(init=True, frozen=True)
+class QChatBboxMessage(QChatMessage):
+ author: str
+ avatar: Optional[str]
+ crs_wkt: str
+ crs_authid: str
+ xmin: float
+ xmax: float
+ ymin: float
+ ymax: float
diff --git a/qtribu/logic/qchat_websocket.py b/qtribu/logic/qchat_websocket.py
index eb38cc28..75d31837 100644
--- a/qtribu/logic/qchat_websocket.py
+++ b/qtribu/logic/qchat_websocket.py
@@ -7,6 +7,7 @@
from qgis.PyQt.QtCore import QObject, QUrl, pyqtSignal
from qtribu.constants import (
+ QCHAT_MESSAGE_TYPE_BBOX,
QCHAT_MESSAGE_TYPE_CRS,
QCHAT_MESSAGE_TYPE_EXITER,
QCHAT_MESSAGE_TYPE_GEOJSON,
@@ -18,6 +19,7 @@
QCHAT_MESSAGE_TYPE_UNCOMPLIANT,
)
from qtribu.logic.qchat_messages import (
+ QChatBboxMessage,
QChatCrsMessage,
QChatExiterMessage,
QChatGeojsonMessage,
@@ -72,6 +74,7 @@ def __init__(self):
like_message_received = pyqtSignal(QChatLikeMessage)
geojson_message_received = pyqtSignal(QChatGeojsonMessage)
crs_message_received = pyqtSignal(QChatCrsMessage)
+ bbox_message_received = pyqtSignal(QChatBboxMessage)
def open(self, qchat_instance_uri: str, room: str) -> None:
"""
@@ -136,3 +139,5 @@ def on_message_received(self, text: str) -> None:
self.geojson_message_received.emit(QChatGeojsonMessage(**message))
elif msg_type == QCHAT_MESSAGE_TYPE_CRS:
self.crs_message_received.emit(QChatCrsMessage(**message))
+ elif msg_type == QCHAT_MESSAGE_TYPE_BBOX:
+ self.bbox_message_received.emit(QChatBboxMessage(**message))