8#include "GeoDataTreeModel.h"
12#include <QItemSelectionModel>
17#include "FileManager.h"
18#include "GeoDataCamera.h"
19#include "GeoDataContainer.h"
20#include "GeoDataDocument.h"
21#include "GeoDataExtendedData.h"
22#include "GeoDataFlyTo.h"
23#include "GeoDataFolder.h"
24#include "GeoDataIconStyle.h"
25#include "GeoDataLinearRing.h"
26#include "GeoDataListStyle.h"
27#include "GeoDataLookAt.h"
28#include "GeoDataMultiGeometry.h"
29#include "GeoDataObject.h"
30#include "GeoDataPlacemark.h"
31#include "GeoDataPlaylist.h"
32#include "GeoDataPoint.h"
33#include "GeoDataPolygon.h"
34#include "GeoDataStyle.h"
35#include "GeoDataTour.h"
36#include "GeoDataWait.h"
37#include "MarbleDebug.h"
38#include "MarblePlacemarkModel.h"
45 Private(QAbstractItemModel *model);
48 static void checkParenting(GeoDataObject *
object);
50 GeoDataDocument *m_rootDocument;
51 bool m_ownsRootDocument;
52 QItemSelectionModel m_selectionModel;
57 , m_ownsRootDocument(true)
58 , m_selectionModel(model)
62GeoDataTreeModel::Private::~Private()
64 if (m_ownsRootDocument) {
65 delete m_rootDocument;
69void GeoDataTreeModel::Private::checkParenting(GeoDataObject *
object)
71 if (
const auto container =
dynamic_cast<const GeoDataContainer *
>(
object)) {
72 for (GeoDataFeature *child : container->featureList()) {
73 if (child->parent() != container) {
74 qWarning() <<
"Parenting mismatch for " << child->name();
83 , d(new Private(this))
103 parentItem = d->m_rootDocument;
113 if (
const auto container =
dynamic_cast<const GeoDataContainer *
>(parentItem)) {
115 return container->size();
129 return geometry->size();
135 const GeoDataPlaylist *playlist = tour->playlist();
144 return playlist->size();
160 return tr(
"Popularity");
162 return tr(
"PopIndex",
"Popularity index");
168QHash<int, QByteArray> GeoDataTreeModel::roleNames()
const
192QVariant GeoDataTreeModel::data(
const QModelIndex &index,
int role)
const
195 if (!index.isValid())
198 auto object =
static_cast<GeoDataObject *
>(index.internalPointer());
201 if (index.column() == 0) {
202 if (placemark->countryCode().isEmpty()) {
203 return QVariant(placemark->name());
205 return QVariant(placemark->name() + QLatin1StringView(
" (") + placemark->countryCode() + QLatin1Char(
')'));
208 }
else if (index.column() == 1) {
210 }
else if (index.column() == 2) {
211 return {placemark->popularity()};
212 }
else if (index.column() == 3) {
213 return {placemark->zoomLevel()};
217 if (
const auto feature =
dynamic_cast<const GeoDataFeature *
>(
object)) {
218 if (index.column() == 0) {
219 return QVariant(feature->name());
220 }
else if (index.column() == 1) {
225 auto geometry =
dynamic_cast<GeoDataGeometry *
>(object);
226 if (geometry && index.column() == 1) {
231 if (playlist && index.column() == 0) {
232 return tr(
"Playlist");
235 if (
object && index.column() == 1) {
242 if (folder->style()->listStyle().listItemType() == GeoDataListStyle::RadioFolder
243 || folder->style()->listStyle().listItemType() == GeoDataListStyle::CheckOffOnly) {
244 if (feature->isVisible()) {
252 if (feature->isGloballyVisible()) {
256 if (feature->isVisible()) {
261 }
else if (
auto feature =
dynamic_cast<GeoDataContainer *
>(
object)) {
263 if (folder->style()->listStyle().listItemType() == GeoDataListStyle::RadioFolder) {
264 bool anyVisible =
false;
266 for (; i < folder->
end(); ++i) {
267 if ((*i)->isVisible()) {
277 }
else if (folder->style()->listStyle().listItemType() == GeoDataListStyle::CheckOffOnly) {
279 bool anyVisible =
false;
280 bool allVisible =
true;
281 for (; i < folder->
end(); ++i) {
282 if ((*i)->isVisible()) {
290 }
else if (anyVisible) {
297 if (feature->isGloballyVisible()) {
299 }
else if (feature->isVisible()) {
306 if (
const auto feature =
dynamic_cast<const GeoDataFeature *
>(
object)) {
307 if (feature->style()->iconStyle().icon().isNull()) {
314 if (
const auto feature =
dynamic_cast<const GeoDataFeature *
>(
object)) {
315 return QVariant(feature->description());
321 return {placemark->zoomLevel()};
325 return {placemark->popularity()};
339 if (
const auto container =
dynamic_cast<const GeoDataContainer *
>(placemark->parent())) {
340 return container->customStyle() ? QVariant(QBrush(container->customStyle()->listStyle().backgroundColor())) : QVariant();
345 return placemark->style()->iconStyle().iconPath();
352QModelIndex GeoDataTreeModel::index(
int row,
int column,
const QModelIndex &parent)
const
360 GeoDataObject *parentItem;
363 parentItem = d->m_rootDocument;
365 parentItem =
static_cast<GeoDataObject *
>(
parent.internalPointer());
372 GeoDataObject *childItem =
nullptr;
374 if (
auto container =
dynamic_cast<GeoDataContainer *
>(parentItem)) {
375 childItem = container->child(row);
380 childItem = placemark->geometry();
387 childItem = geometry->child(row);
392 childItem = tour->playlist();
397 childItem = playlist->primitive(row);
407 if (!index.isValid()) {
412 auto childObject =
static_cast<GeoDataObject *
>(index.internalPointer());
416 if (parentObject == d->m_rootDocument) {
423 if (greatParentObject ==
nullptr) {
428 if (
auto greatparentContainer =
dynamic_cast<GeoDataContainer *
>(greatParentObject)) {
432 return createIndex(greatparentContainer->childPosition(parentFeature), 0, parentObject);
448 return createIndex(greatparentMultiGeo->childPosition(parentGeometry), 0, parentObject);
460int GeoDataTreeModel::columnCount(
const QModelIndex &)
const
473 bool bValue = value.
toBool();
475 if (pfolder->style()->listStyle().listItemType() == GeoDataListStyle::RadioFolder) {
478 for (; i < pfolder->
end(); ++i) {
479 (*i)->setVisible(
false);
487 if (folder->style()->listStyle().listItemType() == GeoDataListStyle::RadioFolder
488 || folder->style()->listStyle().listItemType() == GeoDataListStyle::CheckOffOnly) {
490 for (; i < folder->
end(); ++i) {
491 (*i)->setVisible(
false);
493 folder->setVisible(
false);
497 feature->setVisible(bValue);
498 mDebug() <<
"setData " << feature->name();
499 updateFeature(feature);
503 if (
auto feature =
dynamic_cast<GeoDataFeature *
>(
object)) {
505 mDebug() <<
"setData " << feature->name() <<
" " << value.
toString();
506 updateFeature(feature);
514Qt::ItemFlags GeoDataTreeModel::flags(
const QModelIndex &index)
const
516 if (!index.isValid())
519 const auto object =
static_cast<const GeoDataObject *
>(index.internalPointer());
522 const GeoDataObject *
parent = feature->parent();
525 if (parentfolder->style()->listStyle().listItemType() == GeoDataListStyle::RadioFolder) {
527 }
else if (parentfolder->style()->listStyle().listItemType() == GeoDataListStyle::CheckHideChildren) {
534 if (folder->style()->listStyle().listItemType() == GeoDataListStyle::RadioFolder) {
536 }
else if (folder->style()->listStyle().listItemType() == GeoDataListStyle::CheckOffOnly) {
538 bool allVisible =
true;
539 for (; i < folder->
constEnd(); ++i) {
540 if (!(*i)->isVisible()) {
550 }
else if (folder->style()->listStyle().listItemType() == GeoDataListStyle::CheckHideChildren) {
559 if (
dynamic_cast<const GeoDataFeature *
>(
object)) {
560 const GeoDataObject *
parent = object;
564 const auto document =
static_cast<const GeoDataDocument *
>(
parent);
565 if (document->documentRole() == UserDocument) {
579QModelIndex GeoDataTreeModel::index(
const GeoDataObject *
object)
const
581 if (
object ==
nullptr)
600 QList<const GeoDataObject *> ancestors;
602 const GeoDataObject *itup = object;
604 while (itup && (itup != d->m_rootDocument)) {
612 itdown = index(d->m_rootDocument->childPosition(
static_cast<const GeoDataFeature *
>(ancestors.
last())), 0, QModelIndex());
614 while ((ancestors.
size() > 1)) {
615 const auto parent =
static_cast<const GeoDataObject *
>(ancestors.
last());
617 if (
const auto container =
dynamic_cast<const GeoDataContainer *
>(
parent)) {
619 itdown = index(container->childPosition(
static_cast<const GeoDataFeature *
>(ancestors.
last())), 0, itdown);
625 itdown = index(0, 0, itdown);
627 itdown = QModelIndex();
632 itdown = index(multiGeometry->childPosition(
static_cast<const GeoDataGeometry *
>(ancestors.
last())), 0, itdown);
635 itdown = index(0, 0, itdown);
637 for (
int i = 0; i < playlist->
size(); i++) {
638 if (playlist->primitive(i) == ancestors.
last()) {
640 itdown = index(i, 0, itdown);
645 itdown = QModelIndex();
653QItemSelectionModel *GeoDataTreeModel::selectionModel()
655 return &d->m_selectionModel;
661 QModelIndex modelindex = index(
parent);
668 if (row < 0 || row >
parent->size()) {
672 parent->insert(row, feature);
673 d->checkParenting(
parent);
677 qWarning() <<
"GeoDataTreeModel::addFeature (parent " <<
parent <<
" - feature" << feature <<
") : parent not found on the TreeModel";
679 qWarning() <<
"Null pointer in call to GeoDataTreeModel::addFeature (parent " <<
parent <<
" - feature" << feature <<
")";
685 return addFeature(d->m_rootDocument, document);
690 if (row < parent->size()) {
692 GeoDataFeature *feature =
parent->child(row);
703 if (feature && (feature != d->m_rootDocument)) {
711 auto parent =
static_cast<const GeoDataObject *
>(feature->
parent());
713 if (
dynamic_cast<const GeoDataContainer *
>(
parent)) {
714 int row =
static_cast<const GeoDataContainer *
>(feature->
parent())->childPosition(feature);
716 bool removed = removeFeatureRow(
static_cast<GeoDataContainer *
>(feature->
parent()), row);
729 auto container =
static_cast<GeoDataContainer *
>(feature->
parent());
730 int index = removeFeature(feature);
731 Q_ASSERT(index != -1);
732 addFeature(container, feature, index);
735void GeoDataTreeModel::removeDocument(
int index)
737 removeFeatureRow(d->m_rootDocument, index);
742 removeFeature(document);
748 if (d->m_ownsRootDocument) {
749 delete d->m_rootDocument;
752 d->m_ownsRootDocument = (document ==
nullptr);
759 return d->m_rootDocument;
762int GeoDataTreeModel::addTourPrimitive(
const QModelIndex &parent, GeoDataTourPrimitive *primitive,
int row)
767 row = playlist->size();
770 playlist->insertPrimitive(row, primitive);
777bool GeoDataTreeModel::removeTourPrimitive(
const QModelIndex &parent,
int index)
779 auto parentObject =
static_cast<GeoDataObject *
>(
parent.internalPointer());
781 if (playlist->size() > index) {
783 playlist->removePrimitiveAt(index);
791bool GeoDataTreeModel::swapTourPrimitives(
const QModelIndex &parent,
int indexA,
int indexB)
793 auto parentObject =
static_cast<GeoDataObject *
>(
parent.internalPointer());
795 if (indexA > indexB) {
796 qSwap(indexA, indexB);
798 if (indexB - indexA == 1) {
804 playlist->swapPrimitives(indexA, indexB);
805 if (indexB - indexA != 1) {
814#include "moc_GeoDataTreeModel.cpp"
A base class that can hold GeoDataFeatures.
A container for Features, Styles and in the future Schemas.
A base class for all geodata features.
A base class for all geodata features.
A base class for all geodata objects.
const GeoDataObject * parent() const
Provides the parent of the object in GeoDataContainers.
The representation of GeoData in a model This class represents all available data given by kml-data f...
GeoDataTreeModel(QObject *parent=nullptr)
Creates a new GeoDataTreeModel.
void removed(GeoDataObject *object)
insert and remove row don't trigger any signal that proxies forward this signal will refresh geometry...
void setRootDocument(GeoDataDocument *document)
Sets the root document to use.
~GeoDataTreeModel() override
Destroys the GeoDataModel.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Return the number of Items in the Model.
QModelIndex parent(const QModelIndex &index) const override
virtual const char * nodeType() const =0
Provides type information for downcasting a GeoNode.
@ VisualCategoryRole
The category.
@ GmtRole
The Greenwich Mean Time.
@ LongitudeRole
The longitude in degree (for use in QML)
@ PopularityIndexRole
The popularity index.
@ DstRole
The Daylight Saving Time.
@ PopularityRole
The popularity.
@ LatitudeRole
The latitude in degree (for use in QML)
@ DescriptionRole
The description.
@ ObjectPointerRole
The pointer to a specific object.
@ GeoTypeRole
The geo type (e.g. city or mountain)
@ CountryCodeRole
The country code.
@ GeometryRole
The GeoDataGeometry geometry.
@ PopulationRole
The population.
@ CoordinateRole
The GeoDataCoordinates coordinate.
@ IconPathRole
Path to the image, if known.
Q_SCRIPTABLE QString camera()
Binds a QML item to a specific geodetic location in screen coordinates.
T * geodata_cast(GeoDataObject *node)
Returns the given node cast to type T if the node was instantiated as type T; otherwise returns 0.
QAbstractItemModel(QObject *parent)
void beginInsertRows(const QModelIndex &parent, int first, int last)
bool beginMoveRows(const QModelIndex &sourceParent, int sourceFirst, int sourceLast, const QModelIndex &destinationParent, int destinationChild)
void beginRemoveRows(const QModelIndex &parent, int first, int last)
QModelIndex createIndex(int row, int column, const void *ptr) const const
bool hasIndex(int row, int column, const QModelIndex &parent) const const
virtual QHash< int, QByteArray > roleNames() const const
void append(QList< T > &&value)
const_iterator constBegin() const const
const_iterator constEnd() const const
bool isEmpty() const const
qsizetype size() const const
void * internalPointer() const const
bool isValid() const const
QObject * parent() const const
QString tr(const char *sourceText, const char *disambiguation, int n)
QString fromLatin1(QByteArrayView str)
QVariant fromValue(T &&value)
bool toBool() const const
QString toString() const const