1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 //
3 // SPDX-FileCopyrightText: 2006-2007 Torsten Rahn <tackat@kde.org>
4 // SPDX-FileCopyrightText: 2007 Inge Wallin <ingwa@kde.org>
5 //
6
7 #include <QApplication>
8 #include <QFile>
9 #include <QDir>
10 #include <QLocale>
11 #include <QTranslator>
12 #include <QStandardPaths>
13
14 #include "QtMainWindow.h"
15
16 #include "MapThemeManager.h"
17 #include "MarbleWidgetInputHandler.h"
18 #include "MarbleDirs.h"
19 #include "MarbleDebug.h"
20 #include "MarbleTest.h"
21 #include "MarbleLocale.h"
22 #include "GeoUriParser.h"
23
24 #ifdef STATIC_BUILD
25 #include <QtPlugin>
26 Q_IMPORT_PLUGIN(qjpeg)
27 Q_IMPORT_PLUGIN(qsvg)
28 #endif
29
30 #ifdef Q_OS_MACX
31 //for getting app bundle path
32 #include <ApplicationServices/ApplicationServices.h>
33 #endif
34
35 using namespace Marble;
36
37 // load translation file from normal "KDE Applications" packaging installation
loadTranslation(const QString & localeDirName,QApplication & app)38 static bool loadTranslation(const QString &localeDirName, QApplication &app)
39 {
40 const QString subPath = QLatin1String("locale/") + localeDirName + QLatin1String("/LC_MESSAGES/marble_qt.qm");
41 const QString fullPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, subPath);
42 if (fullPath.isEmpty()) {
43 return false;
44 }
45
46 QTranslator* translator = new QTranslator(&app);
47 if (!translator->load(fullPath)) {
48 delete translator;
49 return false;
50 }
51
52 app.installTranslator(translator);
53
54 return true;
55 }
56
57 // load KDE translators system based translations
58 // TODO: document other possible supported translation systems, if any, and where their catalog files are
loadTranslations(QApplication & app)59 static void loadTranslations(QApplication &app)
60 {
61 // Quote from ecm_create_qm_loader created code:
62 // The way Qt translation system handles plural forms makes it necessary to
63 // have a translation file which contains only plural forms for `en`.
64 // That's why we load the `en` translation unconditionally, then load the
65 // translation for the current locale to overload it.
66 const QString en(QStringLiteral("en"));
67
68 loadTranslation(en, app);
69
70 QLocale locale = QLocale::system();
71 if (locale.name() != en) {
72 if (!loadTranslation(locale.name(), app)) {
73 loadTranslation(locale.bcp47Name(), app);
74 }
75 }
76 }
77
78
main(int argc,char * argv[])79 int main(int argc, char *argv[])
80 {
81 QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true);
82
83 QApplication app(argc, argv);
84 app.setApplicationName( "Marble Virtual Globe" );
85 app.setOrganizationName( "KDE" );
86 app.setOrganizationDomain( "kde.org" );
87 #if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
88 app.setDesktopFileName(QStringLiteral("org.kde.marble-qt"));
89 #endif
90
91 // Load Qt translation system catalog for libmarblewidget, the plugins and this app
92 loadTranslations(app);
93
94 app.setApplicationDisplayName(MainWindow::tr("Marble - Virtual Globe"));
95
96 // For non static builds on mac and win
97 // we need to be sure we can find the qt image
98 // plugins. In mac be sure to look in the
99 // application bundle...
100
101 #ifdef Q_WS_WIN
102 QApplication::addLibraryPath( QApplication::applicationDirPath()
103 + QDir::separator() + QLatin1String("plugins"));
104 #endif
105 #ifdef Q_OS_MACX
106 QApplication::instance()->setAttribute(Qt::AA_DontShowIconsInMenus);
107 qDebug("Adding qt image plugins to plugin search path...");
108 CFURLRef myBundleRef = CFBundleCopyBundleURL(CFBundleGetMainBundle());
109 CFStringRef myMacPath = CFURLCopyFileSystemPath(myBundleRef, kCFURLPOSIXPathStyle);
110 const char *mypPathPtr = CFStringGetCStringPtr(myMacPath,CFStringGetSystemEncoding());
111 CFRelease(myBundleRef);
112 CFRelease(myMacPath);
113 QString myPath(mypPathPtr);
114 // if we are not in a bundle assume that the app is built
115 // as a non bundle app and that image plugins will be
116 // in system Qt frameworks. If the app is a bundle
117 // lets try to set the qt plugin search path...
118 if (myPath.contains(".app"))
119 {
120 myPath += QLatin1String("/Contents/plugins");
121 QApplication::addLibraryPath( myPath );
122 qDebug( "Added %s to plugin search path", qPrintable( myPath ) );
123 }
124 #endif
125
126 QString marbleDataPath;
127 int dataPathIndex=0;
128 QString mapThemeId;
129 QString tour;
130 QString coordinatesString;
131 QString distanceString;
132 QString geoUriString;
133 MarbleGlobal::Profiles profiles = MarbleGlobal::getInstance()->profiles();
134
135 QStringList args = QApplication::arguments();
136
137 if ( args.contains( "-h" ) || args.contains( "--help" ) ) {
138 qWarning() << "Usage: marble [options] [files]";
139 qWarning();
140 qWarning() << "[files] can be zero, one or more .kml and/or .gpx files to load and show.";
141 qWarning();
142 qWarning() << "general options:";
143 qWarning() << " --marbledatapath=<path> .... Overwrite the compile-time path to map themes and other data";
144 qWarning() << " --geo-uri=<uri> ............ Show map at given geo uri";
145 qWarning() << " --latlon=<coordinates> ..... Show map at given lat lon coordinates";
146 qWarning() << " --distance=<value> ......... Set the distance of the observer to the globe (in km)";
147 qWarning() << " --map=<id> ................. Use map id (e.g. \"earth/openstreetmap/openstreetmap.dgml\")";
148 qWarning() << " --tour=<file> .............. Load a KML tour from the given file and play it";
149 qWarning();
150 qWarning() << "debug options:";
151 qWarning() << " --debug-info ............... write (more) debugging information to the console";
152 qWarning() << " --fps ...................... Show the paint performance (paint rate) in the top left corner";
153 qWarning() << " --runtimeTrace.............. Show the time spent and other debug info of each layer";
154 qWarning() << " --tile-id................... Write the identifier of texture tiles on top of them";
155 qWarning() << " --timedemo ................. Measure the paint performance while moving the map and quit";
156 qWarning() << " --debug-polygons ........... Display the polygon nodes and their index for debugging";
157 qWarning() << " --debug-levels ............. Display OSM placemarks according to the level selected";
158 qWarning();
159 qWarning() << "profile options (note that marble should automatically detect which profile to use. Override that with the options below):";
160 qWarning() << " --highresolution ........... Enforce the profile for devices with high resolution (e.g. desktop computers)";
161 qWarning() << " --nohighresolution ......... Deactivate the profile for devices with high resolution (e.g. desktop computers)";
162
163 return 0;
164 }
165
166 for ( int i = 1; i < args.count(); ++i ) {
167 const QString arg = args.at(i);
168
169 if ( arg == QLatin1String( "--debug-info" ) )
170 {
171 MarbleDebug::setEnabled( true );
172 }
173 else if ( arg.startsWith( QLatin1String( "--marbledatapath=" ), Qt::CaseInsensitive ) )
174 {
175 marbleDataPath = args.at(i).mid(17);
176 }
177 else if ( arg.compare( QLatin1String( "--marbledatapath" ), Qt::CaseInsensitive ) == 0 && i+1 < args.size() ) {
178 dataPathIndex = i + 1;
179 marbleDataPath = args.value( dataPathIndex );
180 ++i;
181 }
182 else if ( arg == QLatin1String( "--highresolution" ) ) {
183 profiles |= MarbleGlobal::HighResolution;
184 }
185 else if ( arg == QLatin1String( "--nohighresolution" ) ) {
186 profiles &= ~MarbleGlobal::HighResolution;
187 }
188 else if ( arg.startsWith( QLatin1String( "--latlon=" ), Qt::CaseInsensitive ) )
189 {
190 coordinatesString = arg.mid(9);
191 }
192 else if ( arg.compare( QLatin1String( "--latlon" ), Qt::CaseInsensitive ) == 0 && i+1 < args.size() ) {
193 ++i;
194 coordinatesString = args.value( i );
195 }
196 else if ( arg.compare( QLatin1String( "--geo-uri=" ), Qt::CaseInsensitive ) == 0 ) {
197 geoUriString = arg.mid(10);
198 }
199 else if ( arg.compare( QLatin1String( "--geo-uri" ), Qt::CaseInsensitive ) == 0 && i+1 < args.size() )
200 {
201 ++i;
202 geoUriString = args.value(i);
203 }
204 else if ( arg.startsWith( QLatin1String( "--distance=" ), Qt::CaseInsensitive ) )
205 {
206 distanceString = arg.mid(11);
207 }
208 else if ( arg.compare( QLatin1String( "--distance" ), Qt::CaseInsensitive ) == 0 && i+1 < args.size() ) {
209 ++i;
210 distanceString = args.value( i );
211 }
212 else if ( arg.startsWith( QLatin1String( "--map=" ), Qt::CaseInsensitive ) )
213 {
214 mapThemeId = arg.mid(6);
215 }
216 else if ( arg.compare( QLatin1String( "--map" ), Qt::CaseInsensitive ) == 0 && i+1 < args.size() ) {
217 ++i;
218 mapThemeId = args.value( i );
219 }
220 else if ( arg.startsWith( QLatin1String( "--tour=" ), Qt::CaseInsensitive ) )
221 {
222 tour = arg.mid(7);
223 }
224 else if ( arg.compare( QLatin1String( "--tour" ), Qt::CaseInsensitive ) == 0 && i+1 < args.size() ) {
225 ++i;
226 tour = args.value( i );
227 }
228 }
229 MarbleGlobal::getInstance()->setProfiles( profiles );
230
231 MarbleLocale::MeasurementSystem const measurement =
232 (MarbleLocale::MeasurementSystem)QLocale::system().measurementSystem();
233 MarbleGlobal::getInstance()->locale()->setMeasurementSystem( measurement );
234
235 QVariantMap cmdLineSettings;
236 if ( !mapThemeId.isEmpty() ) {
237 cmdLineSettings.insert( QLatin1String("mapTheme"), QVariant(mapThemeId) );
238 }
239
240 if ( !coordinatesString.isEmpty() ) {
241 bool success = false;
242 const GeoDataCoordinates coordinates = GeoDataCoordinates::fromString(coordinatesString, success);
243 if ( success ) {
244 QVariantList lonLat;
245 lonLat << QVariant( coordinates.longitude(GeoDataCoordinates::Degree) )
246 << QVariant( coordinates.latitude(GeoDataCoordinates::Degree) );
247 cmdLineSettings.insert( QLatin1String("lonlat"), QVariant(lonLat) );
248 }
249 }
250 if ( !distanceString.isEmpty() ) {
251 bool success = false;
252 const qreal distance = distanceString.toDouble(&success);
253 if ( success ) {
254 cmdLineSettings.insert( QLatin1String("distance"), QVariant(distance) );
255 }
256 }
257 if ( !tour.isEmpty() ) {
258 cmdLineSettings.insert( QLatin1String("tour"), QVariant(tour) );
259 }
260
261 cmdLineSettings.insert( QLatin1String("geo-uri"), QVariant(geoUriString) );
262
263 MainWindow window( marbleDataPath, cmdLineSettings );
264
265 // window.marbleWidget()->rotateTo( 0, 0, -90 );
266 // window.show();
267
268 for ( int i = 1; i < args.count(); ++i ) {
269 const QString arg = args.at(i);
270 if (arg == QLatin1String("--timedemo")) {
271 window.resize(900, 640);
272 MarbleTest marbleTest( window.marbleWidget() );
273 marbleTest.timeDemo();
274 return 0;
275 }
276
277 if (arg == QLatin1String("--fps")) {
278 window.marbleControl()->marbleWidget()->setShowFrameRate( true );
279 }
280 else if (arg == QLatin1String("--tile-id")) {
281 window.marbleControl()->marbleWidget()->setShowTileId(true);
282 }
283 else if (arg == QLatin1String("--runtimeTrace")) {
284 window.marbleControl()->marbleWidget()->setShowRuntimeTrace( true );
285 }
286 else if (arg == QLatin1String("--debug-polygons")) {
287 window.marbleControl()->marbleWidget()->setShowDebugPolygons( true );
288 }
289 else if ( i != dataPathIndex && QFile::exists( arg ) ) {
290 window.addGeoDataFile(arg);
291 }
292 else if (arg == QLatin1String("--debug-levels")) {
293 window.marbleWidget()->setDebugLevelTags(true);
294 }
295 }
296
297 auto const marbleWidget = window.marbleControl()->marbleWidget();
298 bool const debugModeEnabled = marbleWidget->showRuntimeTrace() || marbleWidget->showDebugPolygons() ||
299 marbleWidget->debugLevelTags() || MarbleDebug::isEnabled();
300 marbleWidget->inputHandler()->setDebugModeEnabled(debugModeEnabled);
301
302 return app.exec();
303 }
304