1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 //
3 // SPDX-FileCopyrightText: 2007 Torsten Rahn <tackat@kde.org>
4 // SPDX-FileCopyrightText: 2007 Inge Wallin <ingwa@kde.org>
5 // SPDX-FileCopyrightText: 2009 Jens-Michael Hoffmann <jensmh@gmx.de>
6 //
7
8 #include <KAboutData>
9 #include <KConfig>
10 #include <KConfigGroup>
11 #include <KCrash>
12 #include <KLocalizedString>
13 #include <KSharedConfig>
14
15 #include <QFile>
16 #include <QCommandLineParser>
17 #include <QApplication>
18 #include <QLocale>
19 #include <QStandardPaths>
20 #include <QTranslator>
21
22 #include "ControlView.h"
23 #include "KdeMainWindow.h"
24 #include "GeoUriParser.h"
25 #include "MarbleDebug.h"
26 #include "MapThemeManager.h"
27
28 #include "MarbleTest.h"
29
30 #ifdef STATIC_BUILD
31 #include <QtPlugin>
32 Q_IMPORT_PLUGIN(qjpeg)
33 Q_IMPORT_PLUGIN(qsvg)
34 #endif
35
36 using namespace Marble;
37
38
loadTranslation(const QString & localeDirName,QApplication & app)39 static bool loadTranslation(const QString &localeDirName, QApplication &app)
40 {
41 const QString subPath = QLatin1String("locale/") + localeDirName + QLatin1String("/LC_MESSAGES/marble_qt.qm");
42 const QString fullPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, subPath);
43 if (fullPath.isEmpty()) {
44 return false;
45 }
46
47 QTranslator* translator = new QTranslator(&app);
48 if (!translator->load(fullPath)) {
49 delete translator;
50 return false;
51 }
52
53 app.installTranslator(translator);
54
55 return true;
56 }
57
loadLibAndPluginTranslations(QApplication & app)58 static void loadLibAndPluginTranslations(QApplication &app)
59 {
60 // Quote from ecm_create_qm_loader created code:
61 // The way Qt translation system handles plural forms makes it necessary to
62 // have a translation file which contains only plural forms for `en`.
63 // That's why we load the `en` translation unconditionally, then load the
64 // translation for the current locale to overload it.
65 const QString en(QStringLiteral("en"));
66
67 loadTranslation(en, app);
68
69 QLocale locale = QLocale::system();
70 if (locale.name() != en) {
71 if (!loadTranslation(locale.name(), app)) {
72 loadTranslation(locale.bcp47Name(), app);
73 }
74 }
75 }
76
77
main(int argc,char * argv[])78 int main ( int argc, char *argv[] )
79 {
80 QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true);
81
82 QApplication app( argc, argv );
83
84 // Load Qt translation system catalog for the plugins and libmarblewidget
85 loadLibAndPluginTranslations(app);
86 // Init KF5 translation system
87 KLocalizedString::setApplicationDomain("marble");
88
89
90 KAboutData aboutData( "marble",
91 i18n( "Marble Virtual Globe" ),
92 ControlView::applicationVersion(),
93 i18n( "A World Atlas." ),
94 KAboutLicense::LGPL_V2,
95 i18n( "(c) 2007-%1", QLatin1String("2016") ),
96 QString(),
97 "https://marble.kde.org/" );
98
99 // Active Development Team of Marble
100 aboutData.addAuthor( i18n( "Torsten Rahn" ),
101 i18n( "Developer and Original Author" ),
102 "rahn@kde.org" );
103 aboutData.addAuthor( i18n( "Bernhard Beschow" ),
104 i18n( "WMS Support, Mobile, Performance" ),
105 "bbeschow@cs.tu-berlin.de" );
106 aboutData.addAuthor( i18n( "Thibaut Gridel" ),
107 i18n( "Geodata" ),
108 "tgridel@free.fr" );
109 aboutData.addAuthor( i18n( "Jens-Michael Hoffmann" ),
110 i18n( "OpenStreetMap Integration, OSM Namefinder, Download Management" ),
111 "jmho@c-xx.com" );
112 aboutData.addAuthor( i18n( "Florian Eßer" ),
113 i18n( "Elevation Profile" ),
114 "f.esser@rwth-aachen.de" );
115 aboutData.addAuthor( i18n( "Wes Hardaker" ),
116 i18n( "APRS Plugin" ),
117 "marble@hardakers.net" );
118 aboutData.addAuthor( i18n( "Bastian Holst" ),
119 i18n( "Online Services support" ),
120 "bastianholst@gmx.de" );
121 aboutData.addAuthor( i18n( "Guillaume Martres" ),
122 i18n( "Satellites" ),
123 "smarter@ubuntu.com" );
124 aboutData.addAuthor( i18n( "Rene Kuettner" ),
125 i18n( "Satellites, Eclipses" ),
126 "rene@bitkanal.net" );
127 aboutData.addAuthor( i18n( "Friedrich W. H. Kossebau" ),
128 i18n( "Plasma Integration, Bugfixes" ),
129 "kossebau@kde.org" );
130 aboutData.addAuthor( i18n( "Dennis Nienhüser" ),
131 i18n( "Routing, Navigation, Mobile" ),
132 "nienhueser@kde.org" );
133 aboutData.addAuthor( i18n( "Niko Sams" ),
134 i18n( "Routing, Elevation Profile" ),
135 "niko.sams@gmail.com" );
136 aboutData.addAuthor( i18n( "Patrick Spendrin" ),
137 i18n( "Core Developer: KML and Windows support" ),
138 "pspendrin@gmail.com" );
139 aboutData.addAuthor( i18n( "Eckhart Wörner" ),
140 i18n( "Bugfixes" ),
141 "kde@ewsoftware.de" );
142
143 // Developers:
144
145 aboutData.addAuthor( i18n( "Inge Wallin" ),
146 i18n( "Core Developer and Co-Maintainer" ),
147 "inge@lysator.liu.se" );
148 aboutData.addAuthor( i18n( "Henry de Valence" ),
149 i18n( "Core Developer: Marble Runners, World-Clock Plasmoid" ),
150 "hdevalence@gmail.com" );
151 aboutData.addAuthor( i18n( "Pino Toscano" ),
152 i18n( "Network plugins" ),
153 "pino@kde.org" );
154 aboutData.addAuthor( i18n( "Harshit Jain" ),
155 i18n( "Planet filter" ),
156 "sonu.itbhu@googlemail.com" );
157 aboutData.addAuthor( i18n( "Simon Edwards" ),
158 i18n( "Marble Python Bindings" ),
159 "simon@simonzone.com" );
160 aboutData.addAuthor( i18n( "Magnus Valle" ),
161 i18n( "Historical Maps" ),
162 "" );
163 aboutData.addAuthor( i18n( "Médéric Boquien" ),
164 i18n( "Astronomical Observatories" ),
165 "mboquien@free.fr" );
166
167 // ESA Summer of Code in Space
168 aboutData.addAuthor( i18n( "Rene Kuettner" ),
169 i18n( "ESA Summer of Code in Space 2012 Project:"
170 " Visualization of planetary satellites" ),
171 "rene@bitkanal.net" );
172 aboutData.addAuthor( i18n( "Guillaume Martres" ),
173 i18n( "ESA Summer of Code in Space 2011 Project:"
174 " Visualization of Satellite Orbits" ),
175 "smarter@ubuntu.com" );
176
177 // Google Summer of Code
178 aboutData.addAuthor( i18n( "Konstantin Oblaukhov" ),
179 i18n( "Google Summer of Code 2011 Project:"
180 " OpenStreetMap Vector Rendering" ),
181 "oblaukhov.konstantin@gmail.com" );
182 aboutData.addAuthor( i18n( "Daniel Marth" ),
183 i18n( "Google Summer of Code 2011 Project:"
184 " Marble Touch on MeeGo" ),
185 "danielmarth@gmx.at" );
186 aboutData.addAuthor( i18n( "Gaurav Gupta" ),
187 i18n( "Google Summer of Code 2010 Project:"
188 " Bookmarks" ),
189 "1989.gaurav@gmail.com" );
190 aboutData.addAuthor( i18n( "Harshit Jain " ),
191 i18n( "Google Summer of Code 2010 Project:"
192 " Time Support" ),
193 "hjain.itbhu@gmail.com" );
194 aboutData.addAuthor( i18n( "Siddharth Srivastava" ),
195 i18n( "Google Summer of Code 2010 Project:"
196 " Turn-by-turn Navigation" ),
197 "akssps011@gmail.com" );
198 aboutData.addAuthor( i18n( "Andrew Manson" ),
199 i18n( "Google Summer of Code 2009 Project:"
200 " OSM Annotation" ),
201 "g.real.ate@gmail.com" );
202 aboutData.addAuthor( i18n( "Bastian Holst" ),
203 i18n( "Google Summer of Code 2009 Project:"
204 " Online Services" ),
205 "bastianholst@gmx.de" );
206 aboutData.addAuthor( i18n( "Patrick Spendrin" ),
207 i18n( "Google Summer of Code 2008 Project:"
208 " Vector Tiles for Marble" ),
209 "pspendrin@gmail.com" );
210 aboutData.addAuthor( i18n( "Shashank Singh" ),
211 i18n( "Google Summer of Code 2008 Project:"
212 " Panoramio / Wikipedia -photo support for Marble" ),
213 "shashank.personal@gmail.com" );
214 aboutData.addAuthor( i18n( "Carlos Licea" ),
215 i18n( "Google Summer of Code 2007 Project:"
216 " Equirectangular Projection (\"Flat Map\")" ),
217 "carlos.licea@kdemail.net" );
218 aboutData.addAuthor( i18n( "Andrew Manson" ),
219 i18n( "Google Summer of Code 2007 Project:"
220 " GPS Support for Marble" ),
221 "g.real.ate@gmail.com" );
222 aboutData.addAuthor( i18n( "Murad Tagirov" ),
223 i18n( "Google Summer of Code 2007 Project:"
224 " KML Support for Marble" ),
225 "tmurad@gmail.com" );
226
227 // Developers
228 aboutData.addAuthor( i18n( "Simon Schmeisser" ),
229 i18n( "Development & Patches" ));
230 aboutData.addAuthor( i18n( "Claudiu Covaci" ),
231 i18n( "Development & Patches" ));
232 aboutData.addAuthor( i18n( "David Roberts" ),
233 i18n( "Development & Patches" ));
234 aboutData.addAuthor( i18n( "Nikolas Zimmermann" ),
235 i18n( "Development & Patches" ));
236 aboutData.addAuthor( i18n( "Jan Becker" ),
237 i18n( "Development & Patches" ));
238 aboutData.addAuthor( i18n( "Stefan Asserhäll" ),
239 i18n( "Development & Patches" ));
240 aboutData.addAuthor( i18n( "Laurent Montel" ),
241 i18n( "Development & Patches" ));
242 aboutData.addAuthor( i18n( "Mayank Madan" ),
243 i18n( "Development & Patches" ));
244 aboutData.addAuthor( i18n( "Prashanth Udupa" ),
245 i18n( "Development & Patches" ));
246 aboutData.addAuthor( i18n( "Anne-Marie Mahfouf" ),
247 i18n( "Development & Patches" ));
248 aboutData.addAuthor( i18n( "Josef Spillner" ),
249 i18n( "Development & Patches" ));
250 aboutData.addAuthor( i18n( "Frerich Raabe" ),
251 i18n( "Development & Patches" ));
252 aboutData.addAuthor( i18n( "Frederik Gladhorn" ),
253 i18n( "Development & Patches" ));
254 aboutData.addAuthor( i18n( "Fredrik Höglund" ),
255 i18n( "Development & Patches" ));
256 aboutData.addAuthor( i18n( "Albert Astals Cid" ),
257 i18n( "Development & Patches" ));
258 aboutData.addAuthor( i18n( "Thomas Zander" ),
259 i18n( "Development & Patches" ));
260 aboutData.addAuthor( i18n( "Joseph Wenninger" ),
261 i18n( "Development & Patches" ));
262 aboutData.addAuthor( i18n( "Kris Thomsen" ),
263 i18n( "Development & Patches" ));
264 aboutData.addAuthor( i18n( "Daniel Molkentin" ),
265 i18n( "Development & Patches" ));
266 aboutData.addAuthor( i18n( "Christophe Leske" ),
267 i18n( "Platforms & Distributions" ));
268 aboutData.addAuthor( i18n( "Sebastian Wiedenroth" ),
269 i18n( "Platforms & Distributions" ));
270 aboutData.addAuthor( i18n( "Tim Sutton" ),
271 i18n( "Platforms & Distributions" ));
272 aboutData.addAuthor( i18n( "Christian Ehrlicher" ),
273 i18n( "Platforms & Distributions" ));
274 aboutData.addAuthor( i18n( "Ralf Habacker" ),
275 i18n( "Platforms & Distributions" ));
276 aboutData.addAuthor( i18n( "Steffen Joeris" ),
277 i18n( "Platforms & Distributions" ));
278 aboutData.addAuthor( i18n( "Marcus Czeslinski" ),
279 i18n( "Platforms & Distributions" ));
280 aboutData.addAuthor( i18n( "Marcus D. Hanwell" ),
281 i18n( "Platforms & Distributions" ));
282 aboutData.addAuthor( i18n( "Chitlesh Goorah" ),
283 i18n( "Platforms & Distributions" ));
284 aboutData.addAuthor( i18n( "Nuno Pinheiro" ),
285 i18n( "Artwork" ));
286 aboutData.addAuthor( i18n( "Torsten Rahn" ),
287 i18n( "Artwork" ));
288
289 // Credits
290 aboutData.addCredit( i18n( "Luis Silva" ),
291 i18n( "Various Suggestions & Testing" ));
292 aboutData.addCredit( i18n( "Stefan Jordan" ),
293 i18n( "Various Suggestions & Testing" ));
294 aboutData.addCredit( i18n( "Robert Scott" ),
295 i18n( "Various Suggestions & Testing" ));
296 aboutData.addCredit( i18n( "Lubos Petrovic" ),
297 i18n( "Various Suggestions & Testing" ));
298 aboutData.addCredit( i18n( "Benoit Sigoure" ),
299 i18n( "Various Suggestions & Testing" ));
300 aboutData.addCredit( i18n( "Martin Konold" ),
301 i18n( "Various Suggestions & Testing" ));
302 aboutData.addCredit( i18n( "Matthias Welwarsky" ),
303 i18n( "Various Suggestions & Testing" ));
304 aboutData.addCredit( i18n( "Rainer Endres" ),
305 i18n( "Various Suggestions & Testing" ));
306 aboutData.addCredit( i18n( "Ralf Gesellensetter" ),
307 i18n( "Various Suggestions & Testing" ));
308 aboutData.addCredit( i18n( "Tim Alder" ),
309 i18n( "Various Suggestions & Testing" ));
310 aboutData.addCredit( i18n( "John Layt" ),
311 i18n( "Special thanks for providing an"
312 " important source of inspiration by creating"
313 " Marble's predecessor \"Kartographer\"." ));
314
315 KCrash::setCrashHandler(KCrash::defaultCrashHandler);
316 KCrash::setDrKonqiEnabled(true);
317
318 KAboutData::setApplicationData(aboutData);
319 QApplication::setWindowIcon(QIcon::fromTheme(QStringLiteral("marble")));
320
321 QCommandLineParser parser;
322 aboutData.setupCommandLine(&parser);
323
324 // Autodetect profiles
325 MarbleGlobal::Profiles profiles = MarbleGlobal::getInstance()->profiles();
326
327 QCommandLineOption debugOption( "debug-info", i18n( "Enable debug output" ) );
328 parser.addOption( debugOption );
329 QCommandLineOption levelOption( "debug-levels", i18n( "Display OSM placemarks according to the level selected" ) );
330 parser.addOption( levelOption );
331 QCommandLineOption timeOption( "timedemo", i18n( "Make a time measurement to check performance" ) );
332 parser.addOption( timeOption );
333 QCommandLineOption fpsOption( "fps", i18n( "Show frame rate" ) );
334 parser.addOption( fpsOption );
335 QCommandLineOption tileOption( "tile-id", i18n( "Show tile IDs" ) );
336 parser.addOption( tileOption );
337 QCommandLineOption traceOption( "runtimeTrace", i18n( "Show time spent in each layer" ) );
338 parser.addOption( traceOption );
339 QCommandLineOption dataPathOption("marbledatapath", i18n("Use a different directory <directory> which contains map data."), "directory");
340 parser.addOption( dataPathOption );
341 QCommandLineOption noSmallScreenOption( "nosmallscreen", i18n( "Do not use the interface optimized for small screens" ) );
342 QCommandLineOption smallScreenOption( "smallscreen", i18n( "Use the interface optimized for small screens" ) );
343 parser.addOption( (profiles & MarbleGlobal::SmallScreen) ? noSmallScreenOption : smallScreenOption );
344 QCommandLineOption noHighResOption( "nohighresolution", i18n( "Do not use the interface optimized for high resolutions" ) );
345 QCommandLineOption highResOption( "highresolution", i18n( "Use the interface optimized for high resolutions" ) );
346 parser.addOption( (profiles & MarbleGlobal::HighResolution) ? noHighResOption : highResOption );
347 QCommandLineOption coordinatesOption("latlon", i18n("Show map at given lat lon <coordinates>"), "coordinates");
348 parser.addOption( coordinatesOption );
349 QCommandLineOption geoUriOption("geo-uri", i18n("Show map at given geo <uri>"), "uri");
350 parser.addOption( geoUriOption );
351 QCommandLineOption distanceOption("distance", i18n("Set the distance of the observer to the globe (in km)"), "distance");
352 parser.addOption( distanceOption );
353 QCommandLineOption mapIdOption("map", i18n("Use map <id> (e.g. \"earth/openstreetmap/openstreetmap.dgml\")"), "id");
354 parser.addOption( mapIdOption );
355 parser.addPositionalArgument("file", i18n( "One or more placemark files to be opened") );
356
357 parser.process( app );
358 aboutData.processCommandLine(&parser);
359
360 // use ecm_create_qm_loader(marblewidget_SRCS marble_qt)
361 // in the library src/lib/marble/CMakeList.txt to load the second catalog
362
363 MarbleDebug::setEnabled( parser.isSet( debugOption ) );
364
365 if ( parser.isSet( smallScreenOption ) ) {
366 profiles |= MarbleGlobal::SmallScreen;
367 }
368 else {
369 profiles &= ~MarbleGlobal::SmallScreen;
370 }
371
372 if ( parser.isSet( highResOption ) ) {
373 profiles |= MarbleGlobal::HighResolution;
374 }
375 else {
376 profiles &= ~MarbleGlobal::HighResolution;
377 }
378
379 MarbleGlobal::getInstance()->setProfiles( profiles );
380
381 QString marbleDataPath = parser.value( dataPathOption );
382 MainWindow window( marbleDataPath );
383 window.show();
384
385 if ( parser.isSet( timeOption ) ) {
386 window.resize(900, 640);
387 MarbleTest test( window.marbleWidget() );
388 test.timeDemo();
389 return 0;
390 }
391
392 if ( parser.isSet( fpsOption ) ) {
393 window.marbleControl()->marbleWidget()->setShowFrameRate( true );
394 }
395
396 if (parser.isSet(levelOption)) {
397 window.marbleWidget()->setDebugLevelTags(true);
398 }
399
400 if ( parser.isSet( tileOption ) ) {
401 window.marbleControl()->marbleWidget()->setShowTileId( true );
402 }
403
404 const QString map = parser.value( mapIdOption );
405 if ( !map.isEmpty() ) {
406 window.marbleWidget()->setMapThemeId(map);
407 }
408
409 const QString coordinatesString = parser.value( coordinatesOption );
410 if ( !coordinatesString.isEmpty() ) {
411 bool success = false;
412 const GeoDataCoordinates coordinates = GeoDataCoordinates::fromString(coordinatesString, success);
413 if ( success ) {
414 const qreal longitude = coordinates.longitude(GeoDataCoordinates::Degree);
415 const qreal latitude = coordinates.latitude(GeoDataCoordinates::Degree);
416 window.marbleWidget()->centerOn(longitude, latitude);
417 }
418 }
419
420 const QString geoUriString = parser.value( geoUriOption );
421 if ( !geoUriString.isEmpty() ) {
422 window.marbleControl()->openGeoUri( geoUriString );
423 }
424
425 const QString distance = parser.value( distanceOption );
426 if ( !distance.isEmpty() ) {
427 bool success = false;
428 const qreal distanceValue = distance.toDouble(&success);
429 if ( success )
430 window.marbleWidget()->setDistance(distanceValue);
431 }
432
433 // Read the files that are given on the command line.
434 for( const QString &file: parser.positionalArguments() ) {
435 // FIXME: Use openUrl( args->url(i) ) instead?
436 if ( QFile::exists( file ) ) {
437 window.marbleControl()->addGeoDataFile( file );
438 }
439 }
440
441 return app.exec();
442 }
443