1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 //
3 // SPDX-FileCopyrightText: 2014 Abhinav Gangwar <abhgang@gmail.com>
4 //
5 
6 // Self
7 #include "CountryByFlag.h"
8 
9 // Qt
10 #include <QTime>
11 #include <QImage>
12 #include <QString>
13 #include <QVector>
14 #include <QVariant>
15 #include <QVariantList>
16 
17 // Marble
18 #include <marble/MarbleWidget.h>
19 #include <marble/MarbleModel.h>
20 #include <marble/GeoDataTreeModel.h>
21 #include <marble/MarbleDirs.h>
22 #include <marble/MarbleDebug.h>
23 #include <marble/MarblePlacemarkModel.h>
24 
25 #include <marble/GeoDataDocument.h>
26 #include <marble/GeoDataPlacemark.h>
27 
28 namespace Marble
29 {
30 class CountryByFlagPrivate
31 {
32 public:
CountryByFlagPrivate(MarbleWidget * marbleWidget)33     CountryByFlagPrivate( MarbleWidget *marbleWidget )
34     : m_marbleWidget( marbleWidget ),
35       m_parent( nullptr ),
36       m_countryNames( nullptr )
37     {
38         m_continentsAndOceans
39             << QStringLiteral("Asia") << QStringLiteral("Africa")
40             << QStringLiteral("North America") << QStringLiteral("South America")
41             << QStringLiteral("Antarctica") << QStringLiteral("Europe")
42             << QStringLiteral("Australia")
43             << QStringLiteral("Arctic Ocean") << QStringLiteral("Indian Ocean")
44             << QStringLiteral("North Atlantic Ocean") << QStringLiteral("North Pacific Ocean")
45             << QStringLiteral("South Pacific Ocean") << QStringLiteral("South Atlantic Ocean")
46             << QStringLiteral("Southern Ocean");
47     }
48 
49     MarbleWidget *m_marbleWidget;
50     CountryByFlag *m_parent;
51 
52     /**
53      * Document to store point placemarks which
54      * have country names ( from file "boundaryplacemarks.cache" )
55      */
56     GeoDataDocument *m_countryNames;
57 
58     /*
59      * When I select a random placemark form boundaryplacemarks.cache
60      * it may represent a continent. Since there is no flag
61      * for a continent, we will not use this placemark to post question.
62      * This list will help checking whether the placemark chosen to
63      * post question is a continent/ocean .
64      */
65     QStringList m_continentsAndOceans;
66 };
67 
CountryByFlag(MarbleWidget * marbleWidget)68 CountryByFlag::CountryByFlag( MarbleWidget *marbleWidget )
69     : QObject(),
70       d ( new CountryByFlagPrivate(marbleWidget) )
71 {
72     d->m_parent = this;
73 }
74 
~CountryByFlag()75 CountryByFlag::~CountryByFlag()
76 {
77     delete d->m_countryNames;
78     delete d;
79 }
80 
initiateGame()81 void CountryByFlag::initiateGame()
82 {
83     /**
84      * First remove the GeoDataDocument, which displays
85      * country names, from map.
86      */
87 
88     if ( !d->m_countryNames ) {
89         const GeoDataTreeModel *const treeModel = d->m_marbleWidget->model()->treeModel();
90         for ( int i = 0; i < treeModel->rowCount(); ++i ) {
91             QVariant const data = treeModel->data ( treeModel->index ( i, 0 ), MarblePlacemarkModel::ObjectPointerRole );
92             GeoDataObject *object = qvariant_cast<GeoDataObject*>( data );
93             Q_ASSERT_X( object, "CountryByFlag::initiateGame",
94                         "failed to get valid data from treeModel for GeoDataObject" );
95             if (auto doc = geodata_cast<GeoDataDocument>(object)) {
96                 QFileInfo fileInfo( doc->fileName() );
97                 if (fileInfo.fileName() == QLatin1String("boundaryplacemarks.cache")) {
98                     d->m_countryNames = doc;
99                     break;
100                 }
101             }
102         }
103     }
104 
105     if ( d->m_countryNames ) {
106         d->m_countryNames->setVisible( false );
107         d->m_marbleWidget->model()->treeModel()->updateFeature( d->m_countryNames );
108         d->m_marbleWidget->centerOn( 23.0, 42.0 );
109         d->m_marbleWidget->setDistance( 7500 );
110         d->m_marbleWidget->setHighlightEnabled( false );
111         emit gameInitialized();
112     }
113 }
114 
postQuestion(QObject * gameObject)115 void CountryByFlag::postQuestion( QObject *gameObject )
116 {
117     /**
118      * Find a random placemark
119      */
120     Q_ASSERT_X( d->m_countryNames, "CountryByFlag::postQuestion",
121                 "CountryByFlagPrivate::m_countryNames is NULL" );
122     QVector<GeoDataPlacemark*> countryPlacemarks = d->m_countryNames->placemarkList();
123 
124     uint randomSeed = uint(QTime::currentTime().msec());
125     qsrand( randomSeed );
126 
127     bool found = false;
128     GeoDataPlacemark *placemark = nullptr;
129     QVariantList answerOptions;
130     QString flagPath;
131 
132     while ( !found ) {
133         int randomIndex = qrand()%countryPlacemarks.size();
134         placemark = countryPlacemarks[randomIndex];
135 
136         if ( !d->m_continentsAndOceans.contains(placemark->name(), Qt::CaseSensitive) ) {
137             const QString countryCode = placemark->countryCode().toLower();
138             flagPath = MarbleDirs::path(QLatin1String("flags/flag_") + countryCode + QLatin1String(".svg"));
139             QImage flag = QFile::exists( flagPath ) ? QImage( flagPath ) : QImage();
140             if ( !flag.isNull() ) {
141                 flagPath = QLatin1String("../../../data/flags/flag_") + countryCode + QLatin1String(".svg");
142                 found = true;
143             }
144         }
145     }
146 
147     answerOptions << placemark->name()
148     << countryPlacemarks[qrand()%countryPlacemarks.size()]->name()
149     << countryPlacemarks[qrand()%countryPlacemarks.size()]->name()
150     << countryPlacemarks[qrand()%countryPlacemarks.size()]->name();
151 
152     // Randomize the options in the list answerOptions
153     for ( int i = 0; i < answerOptions.size(); ++i ) {
154         QVariant option = answerOptions.takeAt( qrand()%answerOptions.size() );
155         answerOptions.append( option );
156     }
157     if ( gameObject ) {
158         QMetaObject::invokeMethod( gameObject, "countryByFlagQuestion",
159                                    Q_ARG(QVariant, QVariant(answerOptions)),
160                                    Q_ARG(QVariant, QVariant(flagPath)),
161                                    Q_ARG(QVariant, QVariant(placemark->name())) );
162     }
163 }
164 
165 }   // namespace Marble
166 
167 #include "moc_CountryByFlag.cpp"
168