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