File indexing completed on 2024-04-28 15:39:05

0001 // SPDX-FileCopyrightText: 2021-2022 Tobias Leupold <tl at stonemx dot de>
0002 //
0003 // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004 
0005 // Local includes
0006 #include "GeoDataModel.h"
0007 #include "KGeoTag.h"
0008 #include "MimeHelper.h"
0009 
0010 // Marble includes
0011 #include <marble/GeoDataCoordinates.h>
0012 
0013 // Qt includes
0014 #include <QDebug>
0015 #include <QFileInfo>
0016 #include <QMimeData>
0017 
0018 // C++ includes
0019 #include <algorithm>
0020 
0021 GeoDataModel::GeoDataModel(QObject *parent) : QAbstractListModel(parent)
0022 {
0023 }
0024 
0025 int GeoDataModel::rowCount(const QModelIndex &) const
0026 {
0027     return m_loadedFiles.count();
0028 }
0029 
0030 QVariant GeoDataModel::data(const QModelIndex &index, int role) const
0031 {
0032     if (! index.isValid() || index.row() > m_loadedFiles.count()) {
0033         return QVariant();
0034     }
0035 
0036     if (role == Qt::DisplayRole) {
0037         return m_displayFileNames.at(index.row());
0038     }
0039 
0040     return QVariant();
0041 }
0042 
0043 bool GeoDataModel::contains(const QString &path)
0044 {
0045     return m_loadedFiles.contains(canonicalPath(path));
0046 }
0047 
0048 void GeoDataModel::addTrack(const QString &path, const QVector<QVector<QDateTime>> &times,
0049                             const QVector<QVector<Coordinates>> &segments)
0050 {
0051     Marble::GeoDataLatLonAltBox marbleTrackBox;
0052     QVector<Marble::GeoDataLineString> marbleTracks;
0053 
0054     QVector<QDateTime> dateTimes;
0055     QHash<QDateTime, Coordinates> trackPoints;
0056 
0057     for (int i = 0; i < times.count(); i++) {
0058         Marble::GeoDataLineString lineString;
0059 
0060         for (int j = 0; j < times.at(i).count(); j++) {
0061             const auto &coordinates = segments.at(i).at(j);
0062             const Marble::GeoDataCoordinates marbleCoordinates
0063                 = Marble::GeoDataCoordinates(coordinates.lon(), coordinates.lat(), 0.0,
0064                                             Marble::GeoDataCoordinates::Degree);
0065             lineString.append(marbleCoordinates);
0066 
0067             const auto &dateTime = times.at(i).at(j);
0068             dateTimes.append(dateTime);
0069             trackPoints[dateTime] = coordinates;
0070         }
0071 
0072         const auto box = lineString.latLonAltBox();
0073         if (marbleTrackBox.isEmpty()) {
0074             marbleTrackBox = box;
0075         } else {
0076             marbleTrackBox |= box;
0077         }
0078         marbleTracks.append(lineString);
0079     }
0080 
0081     m_marbleTracks.append(marbleTracks);
0082     m_marbleTrackBoxes.append(marbleTrackBox);
0083 
0084     std::sort(dateTimes.begin(), dateTimes.end());
0085     m_dateTimes.append(dateTimes);
0086     m_trackPoints.append(trackPoints);
0087 
0088     m_loadedFiles.append(canonicalPath(path));
0089     const QFileInfo info(path);
0090     m_displayFileNames.append(info.completeBaseName());
0091 
0092     const auto modelIndex = index(m_displayFileNames.count() - 1, 0);
0093     Q_EMIT dataChanged(modelIndex, modelIndex, { Qt::DisplayRole });
0094 }
0095 
0096 void GeoDataModel::removeTrack(int row)
0097 {
0098     beginRemoveRows(QModelIndex(), row, row);
0099     const auto modelIndex = index(row, 0);
0100     m_loadedFiles.remove(row);
0101     m_displayFileNames.remove(row);
0102     m_marbleTracks.remove(row);
0103     m_marbleTrackBoxes.remove(row);
0104     m_dateTimes.remove(row);
0105     m_trackPoints.remove(row);
0106     Q_EMIT dataChanged(modelIndex, modelIndex, { Qt::DisplayRole });
0107     endRemoveRows();
0108 }
0109 
0110 void GeoDataModel::removeAllTracks()
0111 {
0112     const auto lastRow = m_loadedFiles.count() - 1;
0113     const auto firstModelIndex = index(0, 0);
0114     const auto lastModelIndex = index(lastRow, 0);
0115     beginRemoveRows(QModelIndex(), 0, lastRow);
0116     m_loadedFiles.clear();
0117     m_displayFileNames.clear();
0118     m_marbleTracks.clear();
0119     m_marbleTrackBoxes.clear();
0120     m_dateTimes.clear();
0121     m_trackPoints.clear();
0122     Q_EMIT dataChanged(firstModelIndex, lastModelIndex, { Qt::DisplayRole });
0123     endRemoveRows();
0124 }
0125 
0126 QString GeoDataModel::canonicalPath(const QString &path) const
0127 {
0128     const QFileInfo info(path);
0129     return info.canonicalFilePath();
0130 }
0131 
0132 Marble::GeoDataLatLonAltBox GeoDataModel::trackBox(const QString &path) const
0133 {
0134     return m_marbleTrackBoxes.at(m_loadedFiles.indexOf(canonicalPath(path)));
0135 }
0136 
0137 Coordinates GeoDataModel::trackBoxCenter(const QString &path) const
0138 {
0139     const auto center = trackBox(path).center();
0140     return Coordinates(center.longitude(Marble::GeoDataCoordinates::Degree),
0141                        center.latitude(Marble::GeoDataCoordinates::Degree),
0142                        0.0,
0143                        true);
0144 }
0145 
0146 Marble::GeoDataLatLonAltBox GeoDataModel::trackBox(const QModelIndex &index) const
0147 {
0148     return m_marbleTrackBoxes.at(index.row());
0149 }
0150 
0151 const QVector<QVector<Marble::GeoDataLineString>> &GeoDataModel::marbleTracks() const
0152 {
0153     return m_marbleTracks;
0154 }
0155 
0156 const QVector<QVector<QDateTime>> &GeoDataModel::dateTimes() const
0157 {
0158     return m_dateTimes;
0159 }
0160 
0161 const QVector<QHash<QDateTime, Coordinates>> &GeoDataModel::trackPoints() const
0162 {
0163     return m_trackPoints;
0164 }
0165 
0166 Qt::DropActions GeoDataModel::supportedDropActions() const
0167 {
0168     return Qt::CopyAction | Qt::MoveAction;
0169 }
0170 
0171 Qt::ItemFlags GeoDataModel::flags(const QModelIndex &index) const
0172 {
0173     Qt::ItemFlags defaultFlags = QAbstractListModel::flags(index);
0174 
0175     if (index.isValid()) {
0176         return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
0177     } else {
0178         return Qt::ItemIsDropEnabled | defaultFlags;
0179     }
0180 }
0181 
0182 bool GeoDataModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int, int,
0183                                    const QModelIndex &) const
0184 {
0185     if (! (action & (Qt::CopyAction | Qt::MoveAction)) || ! data->hasUrls()) {
0186         return false;
0187     }
0188 
0189     if (MimeHelper::getUsablePaths(KGeoTag::DroppedOnTrackList, data).isEmpty()) {
0190         return false;
0191     }
0192 
0193     return true;
0194 }
0195 
0196 bool GeoDataModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int, int,
0197                                     const QModelIndex &)
0198 {
0199     if (! (action & (Qt::CopyAction | Qt::MoveAction)) || ! data->hasUrls()) {
0200         return false;
0201     }
0202 
0203     Q_EMIT requestAddFiles(MimeHelper::getUsablePaths(KGeoTag::DroppedOnTrackList, data));
0204 
0205     return true;
0206 }