7#include "localization.h" 
   11#include <style/mapcssdeclaration_p.h> 
   12#include <style/mapcssstate_p.h> 
   14#include <KOSMIndoorMap/MapCSSParser> 
   15#include <KOSMIndoorMap/MapCSSResult> 
   17#include <KLocalizedString> 
   27RoomModel::RoomModel(
QObject *parent)
 
   29    , m_langs(
OSM::Languages::fromQLocale(
QLocale()))
 
   31    connect(
this, &RoomModel::timeChanged, 
this, [
this]() {
 
   39RoomModel::~RoomModel() = 
default;
 
   41MapData RoomModel::mapData()
 const 
   46void RoomModel::setMapData(
const MapData &data)
 
   52    if (m_style.isEmpty()) {
 
   54        m_style = p.parse(QStringLiteral(
":/org.kde.kosmindoormap/assets/quick/room-model.mapcss"));
 
   56            qWarning() << p.errorMessage();
 
   65    if (!m_data.isEmpty()) {
 
   66        m_style.compile(m_data.dataSet());
 
   72int RoomModel::rowCount(
const QModelIndex &parent)
 const 
   79    return (
int)m_rooms.size();
 
   82QVariant RoomModel::data(
const QModelIndex &index, 
int role)
 const 
   88    const auto &room = m_rooms[
index.row()];
 
   97            const auto types = room.element.tagValue(
"room", 
"amenity").split(
';');
 
   99            for (
const auto &type : types) {
 
  108            return QLocale().createSeparatedList(l);
 
  112            const auto center = room.element.center();
 
  120            return QString::fromUtf8(room.buildingElement.tagValue(m_langs, 
"name", 
"local_ref", 
"ref"));
 
  123            auto s = 
QString::fromUtf8(room.levelElement.tagValue(m_langs, 
"name", 
"level:ref"));
 
  128            if ((room.level / 10) == 0) {
 
  129                return i18n(
"Ground floor");
 
  131            return i18n(
"Floor %1", room.level / 10); 
 
  147QHash<int, QByteArray> RoomModel::roleNames()
 const 
  153    r.insert(CoordinateRole, 
"coordinate");
 
  164    return (
int)m_buildings.size();
 
  169    return rowCount() == 0;
 
  172void RoomModel::ensurePopulated()
 const 
  174    if (m_rooms.empty() && !m_data.isEmpty()) {
 
  177        const_cast<RoomModel*
>(
this)->populateModel();
 
  181void RoomModel::populateModel()
 
  184    const auto buildingKey = m_data.dataSet().tagKey(
"building");
 
  185    const auto nameKey = m_data.dataSet().tagKey(
"name");
 
  186    const auto refKey = m_data.dataSet().tagKey(
"ref");
 
  188    for (
auto it = m_data.levelMap().begin(); it != m_data.levelMap().end(); ++it) {
 
  189        for (
const auto &e : (*it).second) {
 
  190            if (e.type() == OSM::Type::Node || !OSM::contains(m_data.boundingBox(), e.center())) {
 
  193            if (e.hasTag(buildingKey) && (e.hasTag(nameKey) || e.hasTag(refKey))) {
 
  195                building.element = e;
 
  197                m_buildings.push_back(std::move(building));
 
  203    const auto indoorKey = m_data.dataSet().tagKey(
"indoor");
 
  204    for (
auto it = m_data.levelMap().begin(); it != m_data.levelMap().end(); ++it) {
 
  205        for (
const auto &e : (*it).second) {
 
  206            if (e.type() == OSM::Type::Node || !OSM::contains(m_data.boundingBox(), e.center())) {
 
  209            if (e.tagValue(indoorKey) == 
"level") {
 
  215                for (
auto &building : m_buildings) {
 
  217                    if (OSM::intersects(e.boundingBox(), building.element.boundingBox())) {
 
  218                        building.levels.push_back(level);
 
  227    MapCSSResult filterResult;
 
  228    OpeningHoursCache ohCache;
 
  229    ohCache.setMapData(mapData());
 
  230    ohCache.setTimeRange(m_beginTime, m_endTime);
 
  232    for (
auto it = m_data.levelMap().begin(); it != m_data.levelMap().end(); ++it) {
 
  233        for (
const auto &e : (*it).second) {
 
  234            if (e.type() == OSM::Type::Node || !OSM::contains(m_data.boundingBox(), e.center())) {
 
  238            MapCSSState filterState;
 
  239            filterState.element = e;
 
  240            filterState.openingHours = &ohCache;
 
  241            m_style.initializeState(filterState);
 
  242            m_style.evaluate(filterState, filterResult);
 
  244            const auto &res = filterResult[{}];
 
  251            room.level = (*it).first.numericLevel(); 
 
  254            for (
auto &building :m_buildings) {
 
  256                if (OSM::intersects(e.boundingBox(), building.element.boundingBox())) {
 
  257                    room.buildingElement = building.element;
 
  258                    ++building.roomCount;
 
  261                    for (
const auto &level : building.levels) {
 
  262                        if (
level.level == room.level) {
 
  263                            room.levelElement = 
level.element;
 
  272            const auto name = filterResult[{}].resolvedTagValue(m_langs, 
"name", filterState);
 
  276            m_rooms.push_back(std::move(room));
 
  284    std::sort(m_rooms.begin(), m_rooms.end(), [](
const auto &lhs, 
const auto &rhs) {
 
  285        if (lhs.element == rhs.element) {
 
  286            return std::abs(lhs.level) < std::abs(rhs.level);
 
  288        return lhs.element < rhs.element;
 
  290    m_rooms.erase(std::unique(m_rooms.begin(), m_rooms.end(), [](
const auto &lhs, 
const auto &rhs) {
 
  291        return lhs.element == rhs.element;
 
  298    std::sort(m_rooms.begin(), m_rooms.end(), [](
const auto &lhs, 
const auto &rhs) {
 
  299        return lhs.buildingElement < rhs.buildingElement;
 
  303    m_buildings.erase(std::remove_if(m_buildings.begin(), m_buildings.end(), [](
const auto &b) { return b.roomCount == 0; }), m_buildings.end());
 
  305    qCDebug(Log) << m_buildings.size() << 
"buildings found";
 
  306    qCDebug(Log) << m_rooms.size() << 
"rooms found";
 
  312    if (name.isEmpty()) {
 
  317    for (
auto it = m_rooms.begin(); it != m_rooms.end(); ++it) {
 
  320            return (
int)std::distance(m_rooms.begin(), it);
 
 
  327#include "moc_roommodel.cpp" 
bool hasError() const
Returns true if an error occured during parsing and the returned style is invalid.
 
Raw OSM map data, separated by levels.
 
Q_INVOKABLE int findRoom(const QString &name) const
Tries to identify the given room name or number and returns the row index if found.
 
int buildingCount
Number of buildings found in the model data.
 
bool isEmpty
Returns true if there are no rooms in the current map data.
 
@ TypeNameRole
Type of the room as translated human readable text, if set.
 
@ NumberRole
room number, if set
 
@ LevelRole
numeric level for positioning rather than for display
 
@ ElementRole
OSM element for this room.
 
@ LevelShortNameRole
Name of the floor the room is on (short form, if available)
 
@ NameRole
room name, if set
 
@ LevelLongNameRole
Name of the floor the room is on (long form, if available)
 
@ BuildingNameRole
Name of the building the room is in.
 
QString i18n(const char *text, const TYPE &arg...)
 
QString amenityType(const char *value, Localization::TranslationOption opt=Localization::ReturnUnknownKey)
Translated name for an amenity tag value (after list splitting).
 
OSM-based multi-floor indoor maps for buildings.
 
QStringView level(QStringView ifopt)
 
Low-level types and functions to work with raw OSM data as efficiently as possible.
 
bool checkIndex(const QModelIndex &index, CheckIndexOptions options) const const
 
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const=0
 
virtual QModelIndex parent(const QModelIndex &index) const const=0
 
virtual QHash< int, QByteArray > roleNames() const const
 
void push_back(parameter_type value)
 
QString fromUtf8(QByteArrayView str)
 
QString number(double n, char format, int precision)
 
QChar first() const const
 
QTextStream & center(QTextStream &stream)
 
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
 
QVariant fromValue(T &&value)