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