Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature(qchat): send and receive a crs message #219

Merged
merged 1 commit into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions qtribu/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,3 +240,4 @@ def local_path(self, base_path: Path = Path().home() / ".geotribu/cdn/") -> Path
QCHAT_MESSAGE_TYPE_EXITER = "exiter"
QCHAT_MESSAGE_TYPE_LIKE = "like"
QCHAT_MESSAGE_TYPE_GEOJSON = "geojson"
QCHAT_MESSAGE_TYPE_CRS = "crs"
36 changes: 32 additions & 4 deletions qtribu/gui/dck_qchat.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

# PyQGIS
from PyQt5 import QtWebSockets # noqa QGS103
from qgis.core import Qgis, QgsApplication, QgsJsonExporter, QgsMapLayer
from qgis.core import Qgis, QgsApplication, QgsJsonExporter, QgsMapLayer, QgsProject
from qgis.gui import QgisInterface, QgsDockWidget
from qgis.PyQt import uic
from qgis.PyQt.QtCore import QPoint, Qt
Expand All @@ -31,6 +31,7 @@
CHEATCODE_IAMAROBOT,
CHEATCODE_QGIS_PRO_LICENSE,
CHEATCODES,
QCHAT_MESSAGE_TYPE_CRS,
QCHAT_MESSAGE_TYPE_GEOJSON,
QCHAT_MESSAGE_TYPE_IMAGE,
QCHAT_MESSAGE_TYPE_LIKE,
Expand All @@ -41,12 +42,14 @@
from qtribu.gui.qchat_tree_widget_items import (
MESSAGE_COLUMN,
QChatAdminTreeWidgetItem,
QChatCrsTreeWidgetItem,
QChatGeojsonTreeWidgetItem,
QChatImageTreeWidgetItem,
QChatTextTreeWidgetItem,
)
from qtribu.logic.qchat_api_client import QChatApiClient
from qtribu.logic.qchat_messages import (
QChatCrsMessage,
QChatExiterMessage,
QChatGeojsonMessage,
QChatImageMessage,
Expand Down Expand Up @@ -165,6 +168,7 @@ def __init__(
self.qchat_ws.exiter_message_received.connect(self.on_exiter_message_received)
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)

# send message signal listener
self.lne_message.returnPressed.connect(self.on_send_button_clicked)
Expand Down Expand Up @@ -565,6 +569,13 @@ def on_geojson_message_received(self, message: QChatGeojsonMessage) -> None:
item = QChatGeojsonTreeWidgetItem(self.twg_chat, message)
self.add_tree_widget_item(item)

def on_crs_message_received(self, message: QChatCrsMessage) -> None:
"""
Launched when a CRS message is received from the websocket
"""
item = QChatCrsTreeWidgetItem(self.twg_chat, message)
self.add_tree_widget_item(item)

# endregion

def on_message_clicked(self, item: QTreeWidgetItem, column: int) -> None:
Expand Down Expand Up @@ -606,17 +617,26 @@ def on_custom_context_menu_requested(self, point: QPoint) -> None:

menu = QMenu(self.tr("QChat Menu"), self)

# if this is a geojson
# if this is a geojson message
if type(item) is QChatGeojsonTreeWidgetItem:
load_geojson_action = QAction(
QgsApplication.getThemeIcon("mActionAddLayer.svg"),
self.tr("Load geojson in QGIS"),
self.tr("Load layer in QGIS"),
)
load_geojson_action.triggered.connect(
partial(item.on_click, MESSAGE_COLUMN)
)
menu.addAction(load_geojson_action)

# if this is a crs message
if type(item) is QChatCrsTreeWidgetItem:
set_crs_action = QAction(
QgsApplication.getThemeIcon("mActionSetProjection.svg"),
self.tr("Set current project CRS"),
)
set_crs_action.triggered.connect(partial(item.on_click, MESSAGE_COLUMN))
menu.addAction(set_crs_action)

# like message action if possible
if item.can_be_liked:
like_action = QAction(
Expand Down Expand Up @@ -791,7 +811,15 @@ def on_send_crs_button_clicked(self) -> None:
"""
Action called when the Send CRS button is clicked
"""
QMessageBox.critical(self, self.tr("Send CRS"), self.tr("Not implemented yet"))
crs = QgsProject.instance().crs()
message = QChatCrsMessage(
type=QCHAT_MESSAGE_TYPE_CRS,
author=self.settings.author_nickname,
avatar=self.settings.author_avatar,
crs_wkt=crs.toWkt(),
crs_authid=crs.authid(),
)
self.qchat_ws.send_message(message)

def add_admin_message(self, text: str) -> None:
"""
Expand Down
31 changes: 31 additions & 0 deletions qtribu/gui/qchat_tree_widget_items.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

from qtribu.constants import ADMIN_MESSAGES_AVATAR, ADMIN_MESSAGES_NICKNAME
from qtribu.logic.qchat_messages import (
QChatCrsMessage,
QChatGeojsonMessage,
QChatImageMessage,
QChatTextMessage,
Expand Down Expand Up @@ -238,3 +239,33 @@ def can_be_copied_to_clipboard(self) -> bool:

def copy_to_clipboard(self) -> None:
QgsApplication.instance().clipboard().setText(json.dumps(self.message.geojson))


class QChatCrsTreeWidgetItem(QChatTreeWidgetItem):
def __init__(self, parent: QTreeWidget, message: QChatCrsMessage):
super().__init__(parent, QTime.currentTime(), message.author, message.avatar)
self.message = message
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 QGIS project CRS to the message one
crs = QgsCoordinateReferenceSystem.fromWkt(self.message.crs_wkt)
QgsProject.instance().setCrs(crs)

@property
def liked_message(self) -> str:
return f"<CRS {self.message.crs_authid}>"

@property
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))
8 changes: 8 additions & 0 deletions qtribu/logic/qchat_messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,11 @@ class QChatGeojsonMessage(QChatMessage):
crs_wkt: str
crs_authid: str
geojson: dict


@dataclass(init=True, frozen=True)
class QChatCrsMessage(QChatMessage):
author: str
avatar: Optional[str]
crs_wkt: str
crs_authid: str
5 changes: 5 additions & 0 deletions qtribu/logic/qchat_websocket.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from qgis.PyQt.QtCore import QObject, QUrl, pyqtSignal

from qtribu.constants import (
QCHAT_MESSAGE_TYPE_CRS,
QCHAT_MESSAGE_TYPE_EXITER,
QCHAT_MESSAGE_TYPE_GEOJSON,
QCHAT_MESSAGE_TYPE_IMAGE,
Expand All @@ -17,6 +18,7 @@
QCHAT_MESSAGE_TYPE_UNCOMPLIANT,
)
from qtribu.logic.qchat_messages import (
QChatCrsMessage,
QChatExiterMessage,
QChatGeojsonMessage,
QChatImageMessage,
Expand Down Expand Up @@ -69,6 +71,7 @@ def __init__(self):
exiter_message_received = pyqtSignal(QChatExiterMessage)
like_message_received = pyqtSignal(QChatLikeMessage)
geojson_message_received = pyqtSignal(QChatGeojsonMessage)
crs_message_received = pyqtSignal(QChatCrsMessage)

def open(self, qchat_instance_uri: str, room: str) -> None:
"""
Expand Down Expand Up @@ -131,3 +134,5 @@ def on_message_received(self, text: str) -> None:
self.like_message_received.emit(QChatLikeMessage(**message))
elif msg_type == QCHAT_MESSAGE_TYPE_GEOJSON:
self.geojson_message_received.emit(QChatGeojsonMessage(**message))
elif msg_type == QCHAT_MESSAGE_TYPE_CRS:
self.crs_message_received.emit(QChatCrsMessage(**message))