File indexing completed on 2024-05-12 12:54:41

0001 // SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
0002 // SPDX-License-Identifier: GPL-2.0-or-later
0003 
0004 #include "locationsmodel.h"
0005 
0006 using namespace Quotient;
0007 
0008 LocationsModel::LocationsModel(QObject *parent)
0009     : QAbstractListModel(parent)
0010 {
0011     connect(this, &LocationsModel::roomChanged, this, [this]() {
0012         for (const auto &event : m_room->messageEvents()) {
0013             if (!is<RoomMessageEvent>(*event)) {
0014                 continue;
0015             }
0016             if (event->contentJson()["msgtype"] == "m.location") {
0017                 const auto &e = *event;
0018                 addLocation(eventCast<const RoomMessageEvent>(&e));
0019             }
0020         }
0021         connect(m_room, &NeoChatRoom::aboutToAddHistoricalMessages, this, [this](const auto &events) {
0022             for (const auto &event : events) {
0023                 if (!is<RoomMessageEvent>(*event)) {
0024                     continue;
0025                 }
0026                 if (event->contentJson()["msgtype"] == "m.location") {
0027                     const auto &e = *event;
0028                     addLocation(eventCast<const RoomMessageEvent>(&e));
0029                 }
0030             }
0031         });
0032         connect(m_room, &NeoChatRoom::aboutToAddNewMessages, this, [this](const auto &events) {
0033             for (const auto &event : events) {
0034                 if (!is<RoomMessageEvent>(*event)) {
0035                     continue;
0036                 }
0037                 if (event->contentJson()["msgtype"] == "m.location") {
0038                     const auto &e = *event;
0039                     addLocation(eventCast<const RoomMessageEvent>(&e));
0040                 }
0041             }
0042         });
0043     });
0044 
0045     connect(this, &LocationsModel::rowsInserted, this, &LocationsModel::boundingBoxChanged);
0046 }
0047 
0048 void LocationsModel::addLocation(const RoomMessageEvent *event)
0049 {
0050     const auto uri = event->contentJson()["org.matrix.msc3488.location"]["uri"].toString();
0051     const auto parts = uri.mid(4).split(QLatin1Char(','));
0052     if (parts.size() < 2) {
0053         qWarning() << "invalid geo: URI" << uri;
0054         return;
0055     }
0056     const auto latitude = parts[0].toFloat();
0057     const auto longitude = parts[1].toFloat();
0058     beginInsertRows(QModelIndex(), m_locations.size(), m_locations.size() + 1);
0059     m_locations += LocationData{
0060         .eventId = event->id(),
0061         .latitude = latitude,
0062         .longitude = longitude,
0063         .content = event->contentJson(),
0064         .author = dynamic_cast<NeoChatUser *>(m_room->user(event->senderId())),
0065     };
0066     endInsertRows();
0067 }
0068 
0069 NeoChatRoom *LocationsModel::room() const
0070 {
0071     return m_room;
0072 }
0073 
0074 void LocationsModel::setRoom(NeoChatRoom *room)
0075 {
0076     if (m_room) {
0077         disconnect(this, nullptr, m_room, nullptr);
0078     }
0079     m_room = room;
0080     Q_EMIT roomChanged();
0081 }
0082 
0083 QHash<int, QByteArray> LocationsModel::roleNames() const
0084 {
0085     return {
0086         {LongitudeRole, "longitude"},
0087         {LatitudeRole, "latitude"},
0088         {TextRole, "text"},
0089         {AssetRole, "asset"},
0090         {AuthorRole, "author"},
0091     };
0092 }
0093 
0094 QVariant LocationsModel::data(const QModelIndex &index, int roleName) const
0095 {
0096     auto row = index.row();
0097     if (roleName == LongitudeRole) {
0098         return m_locations[row].longitude;
0099     } else if (roleName == LatitudeRole) {
0100         return m_locations[row].latitude;
0101     } else if (roleName == TextRole) {
0102         return m_locations[row].content["body"_ls].toString();
0103     } else if (roleName == AssetRole) {
0104         return m_locations[row].content["org.matrix.msc3488.asset"_ls].toObject()["type"_ls].toString();
0105     } else if (roleName == AuthorRole) {
0106         return m_room->getUser(m_locations[row].author);
0107     }
0108     return {};
0109 }
0110 
0111 int LocationsModel::rowCount(const QModelIndex &parent) const
0112 {
0113     Q_UNUSED(parent);
0114     return m_locations.size();
0115 }
0116 
0117 QRectF LocationsModel::boundingBox() const
0118 {
0119     QRectF bbox(QPointF(180.0, 90.0), QPointF(-180.0, -90.0));
0120     for (auto i = 0; i < rowCount(); ++i) {
0121         const auto lat = data(index(i, 0), LatitudeRole).toDouble();
0122         const auto lon = data(index(i, 0), LongitudeRole).toDouble();
0123 
0124         bbox.setLeft(std::min(bbox.left(), lon));
0125         bbox.setRight(std::max(bbox.right(), lon));
0126         bbox.setTop(std::min(bbox.top(), lat));
0127         bbox.setBottom(std::max(bbox.bottom(), lat));
0128     }
0129     return bbox;
0130 }
0131 
0132 #include "moc_locationsmodel.cpp"