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&szlig;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