locationqueryoverlayproxymodel.cpp 4.98 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
/*
    SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org>

    SPDX-License-Identifier: LGPL-2.0-or-later
*/

#include "locationqueryoverlayproxymodel.h"

#include <KPublicTransport/Location>
#include <KPublicTransport/LocationQueryModel>

#include <osm/element.h>
13
#include <osm/geomath.h>
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

using namespace KOSMIndoorMap;
using namespace KPublicTransport;

LocationQueryOverlayProxyModel::LocationQueryOverlayProxyModel(QObject *parent)
    : QAbstractListModel(parent)
{
}

LocationQueryOverlayProxyModel::~LocationQueryOverlayProxyModel() = default;

MapData* LocationQueryOverlayProxyModel::mapData() const
{
    return m_data;
}

void LocationQueryOverlayProxyModel::setMapData(MapData* data)
{
    // ### do not check for m_data != data, this does not actually change!
    beginResetModel();
    m_data = data;
35
36
37
38
39
40
41
42

    if (m_data) {
        m_tagKeys.amenity = m_data->dataSet().makeTagKey("amenity");
        m_tagKeys.capacity = m_data->dataSet().makeTagKey("capacity");
        m_tagKeys.realtimeAvailable = m_data->dataSet().makeTagKey("mx:realtime_available");
        m_tagKeys.network = m_data->dataSet().makeTagKey("network");
    }

43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
    initialize();
    endResetModel();
    emit mapDataChanged();
}

QAbstractItemModel* LocationQueryOverlayProxyModel::sourceModel() const
{
    return m_sourceModel;
}

void LocationQueryOverlayProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
{
    if (m_sourceModel == sourceModel) {
        return;
    }
    beginResetModel();
    m_sourceModel = sourceModel;
    initialize();
    endResetModel();
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94

    connect(m_sourceModel, &QAbstractItemModel::modelReset, this, [this]() {
        beginResetModel();
        initialize();
        endResetModel();
    });
    connect(m_sourceModel, &QAbstractItemModel::rowsInserted, this, [this](const QModelIndex &parent, int first, int last) {
        if (parent.isValid() || !m_data) {
            return;
        }
        beginInsertRows({}, first, last);
        for (int i = first; i <= last; ++i) {
            m_nodes.insert(m_nodes.begin() + i, nodeForRow(i));
        }
        endInsertRows();
    });
    connect(m_sourceModel, &QAbstractItemModel::rowsRemoved, this, [this](const QModelIndex &parent, int first, int last) {
        if (parent.isValid() || !m_data) {
            return;
        }
        beginRemoveRows({}, first, last);
        m_nodes.erase(m_nodes.begin() + first, m_nodes.begin() + last);
        endRemoveRows();
    });
    connect(m_sourceModel, &QAbstractItemModel::dataChanged, this, [this](const QModelIndex &first, const QModelIndex &last) {
        if (first.parent().isValid() || last.parent().isValid() || !m_data) {
            return;
        }
        for (int i = first.row(); i <= last.row(); ++i) {
            m_nodes[i] = nodeForRow(i);
        }
        emit dataChanged(index(first.row(), 0), index(last.row(), 0));
    });
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
}

int LocationQueryOverlayProxyModel::rowCount(const QModelIndex &parent) const
{
    if (parent.isValid()) {
        return 0;
    }
    return m_nodes.size();
}

QVariant LocationQueryOverlayProxyModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid()) {
        return {};
    }

    switch (role) {
        case ElementRole:
            return QVariant::fromValue(OSM::Element(&m_nodes[index.row()]));
        case LevelRole:
            return 0;
    }

    return {};
}

QHash<int, QByteArray> LocationQueryOverlayProxyModel::roleNames() const
{
    auto n = QAbstractListModel::roleNames();
    n.insert(ElementRole, "osmElement");
    n.insert(LevelRole, "level");
    return n;
}

void LocationQueryOverlayProxyModel::initialize()
{
    if (!m_data || !m_sourceModel) {
        return;
    }

    m_nodes.clear();
    const auto rows = m_sourceModel->rowCount();
    m_nodes.reserve(rows);
    for (int i = 0; i < rows; ++i) {
139
140
141
        m_nodes.push_back(nodeForRow(i));
    }
}
142

143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
OSM::Node LocationQueryOverlayProxyModel::nodeForRow(int row) const
{
    const auto idx = m_sourceModel->index(row, 0);
    const auto loc = idx.data(LocationQueryModel::LocationRole).value<Location>();

    OSM::Node node;
    node.coordinate = OSM::Coordinate(loc.latitude(), loc.longitude());

    // try to find a matching node in the base OSM data
    for (const auto &n : m_data->dataSet().nodes) {
        if (OSM::distance(n.coordinate, node.coordinate) < 10 && OSM::tagValue(n, m_tagKeys.amenity) == "bicycle_rental") {
            qDebug() << "found matching node, cloning that!" << n.url();
            node = n;
            break;
        }
    }
159

160
161
162
163
164
165
    node.id = m_data->dataSet().nextInternalId();
    OSM::setTagValue(node, m_tagKeys.amenity, "bicycle_rental");
    OSM::setTagValue(node, m_tagKeys.capacity, QByteArray::number(loc.rentalVehicleStation().capacity()));
    OSM::setTagValue(node, m_tagKeys.realtimeAvailable, QByteArray::number(loc.rentalVehicleStation().availableVehicles()));
    if (OSM::tagValue(node, m_tagKeys.network).isEmpty()) {
        OSM::setTagValue(node, m_tagKeys.network, loc.rentalVehicleStation().network().name().toUtf8());
166
    }
167
    return node;
168
}