1 /*
2     SPDX-FileCopyrightText: 2002 Jason Harris <jharris@30doradus.org>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "kstars.h"
8 
9 #include "fov.h"
10 #include "kspaths.h"
11 #include "kstarsdata.h"
12 #include "kstars_debug.h"
13 #include "Options.h"
14 #include "skymap.h"
15 #include "texturemanager.h"
16 #include "projections/projector.h"
17 #include "skycomponents/skymapcomposite.h"
18 #include "skyobjects/ksplanetbase.h"
19 #include "widgets/timespinbox.h"
20 #include "widgets/timestepbox.h"
21 #include "widgets/timeunitbox.h"
22 #include "hips/hipsmanager.h"
23 #include "auxiliary/thememanager.h"
24 
25 #ifdef HAVE_INDI
26 #include "indi/drivermanager.h"
27 #include "indi/guimanager.h"
28 #include "ekos/manager.h"
29 #endif
30 
31 #include <KActionCollection>
32 #include <KActionMenu>
33 #include <KTipDialog>
34 #include <KToggleAction>
35 #include <KToolBar>
36 
37 #include <QMenu>
38 #include <QStatusBar>
39 
40 //This file contains functions that kstars calls at startup (except constructors).
41 //These functions are declared in kstars.h
42 
43 namespace
44 {
45 // A lot of QAction is defined there. In order to decrease amount
46 // of boilerplate code a trick with << operator overloading is used.
47 // This makes code more concise and readable.
48 //
49 // When data type could not used directly. Either because of
50 // overloading rules or because one data type have different
51 // semantics its wrapped into struct.
52 //
53 // Downside is unfamiliar syntax and really unhelpful error
54 // messages due to general abuse of << overloading
55 
56 // Set QAction text
operator <<(QAction * ka,QString text)57 QAction *operator<<(QAction *ka, QString text)
58 {
59     ka->setText(text);
60     return ka;
61 }
62 // Set icon for QAction
operator <<(QAction * ka,const QIcon & icon)63 QAction *operator<<(QAction *ka, const QIcon &icon)
64 {
65     ka->setIcon(icon);
66     return ka;
67 }
68 // Set keyboard shortcut
operator <<(QAction * ka,const QKeySequence sh)69 QAction *operator<<(QAction *ka, const QKeySequence sh)
70 {
71     KStars::Instance()->actionCollection()->setDefaultShortcut(ka, sh);
72     //ka->setShortcut(sh);
73     return ka;
74 }
75 
76 // Add action to group. AddToGroup struct acts as newtype wrapper
77 // in order to allow overloading.
78 struct AddToGroup
79 {
80     QActionGroup *grp;
AddToGroup__anon49b0be1b0111::AddToGroup81     AddToGroup(QActionGroup *g) : grp(g) {}
82 };
operator <<(QAction * ka,AddToGroup g)83 QAction *operator<<(QAction *ka, AddToGroup g)
84 {
85     g.grp->addAction(ka);
86     return ka;
87 }
88 
89 // Set checked property. Checked is newtype wrapper.
90 struct Checked
91 {
92     bool flag;
Checked__anon49b0be1b0111::Checked93     Checked(bool f) : flag(f) {}
94 };
operator <<(QAction * ka,Checked chk)95 QAction *operator<<(QAction *ka, Checked chk)
96 {
97     ka->setCheckable(true);
98     ka->setChecked(chk.flag);
99     return ka;
100 }
101 
102 // Set tool tip. ToolTip is used as newtype wrapper.
103 struct ToolTip
104 {
105     QString tip;
ToolTip__anon49b0be1b0111::ToolTip106     ToolTip(QString msg) : tip(msg) {}
107 };
operator <<(QAction * ka,const ToolTip & tool)108 QAction *operator<<(QAction *ka, const ToolTip &tool)
109 {
110     ka->setToolTip(tool.tip);
111     return ka;
112 }
113 
114 // Create new KToggleAction and connect slot to toggled(bool) signal
newToggleAction(KActionCollection * col,QString name,QString text,QObject * receiver,const char * member)115 QAction *newToggleAction(KActionCollection *col, QString name, QString text, QObject *receiver, const char *member)
116 {
117     QAction *ka = col->add<KToggleAction>(name) << text;
118     QObject::connect(ka, SIGNAL(toggled(bool)), receiver, member);
119     return ka;
120 }
121 }
122 
123 // Resource file override - used by UI tests
124 QString KStars::m_KStarsUIResource = "kstarsui.rc";
setResourceFile(QString const rc)125 bool KStars::setResourceFile(QString const rc)
126 {
127     if (QFile(rc).exists())
128     {
129         m_KStarsUIResource = rc;
130         return true;
131     }
132     else return false;
133 }
134 
135 
initActions()136 void KStars::initActions()
137 {
138     // Check if we have this specific Breeze icon. If not, try to set the theme search path and if appropriate, the icon theme rcc file
139     // in each OS
140     if (!QIcon::hasThemeIcon(QLatin1String("kstars_flag")))
141         KSTheme::Manager::instance()->setIconTheme(KSTheme::Manager::BREEZE_DARK_THEME);
142 
143     QAction *ka;
144 
145     // ==== File menu ================
146     ka = new QAction(QIcon::fromTheme("favorites"), i18n("Download New Data..."), this);
147     connect(ka, &QAction::triggered, this, &KStars::slotDownload);
148     ka->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_N));
149     ka->setWhatsThis(i18n("Downloads new data"));
150     ka->setToolTip(ka->whatsThis());
151     ka->setStatusTip(ka->whatsThis());
152     actionCollection()->addAction(QStringLiteral("get_data"), ka);
153 
154 #ifdef HAVE_CFITSIO
155     actionCollection()->addAction("open_file", this, SLOT(slotOpenFITS()))
156             << i18n("Open Image...") << QIcon::fromTheme("document-open")
157             << QKeySequence(Qt::CTRL + Qt::Key_O);
158 #endif
159     actionCollection()->addAction("export_image", this, SLOT(slotExportImage()))
160             << i18n("&Save Sky Image...")
161             << QIcon::fromTheme("document-export-image");
162 
163     // 2017-09-17 Jasem: FIXME! Scripting does not work properly under non UNIX systems.
164     // It must be updated to use DBus session bus from Qt (like scheduler)
165 #ifndef Q_OS_WIN
166     actionCollection()->addAction("run_script", this, SLOT(slotRunScript()))
167             << i18n("&Run Script...") << QIcon::fromTheme("system-run")
168             << QKeySequence(Qt::CTRL + Qt::Key_R);
169 #endif
170     actionCollection()->addAction("printing_wizard", this, SLOT(slotPrintingWizard()))
171             << i18nc("start Printing Wizard", "Printing &Wizard...");
172     ka = actionCollection()->addAction(KStandardAction::Print, "print", this, SLOT(slotPrint()));
173     ka->setIcon(QIcon::fromTheme("document-print"));
174     //actionCollection()->addAction( KStandardAction::Quit,  "quit",  this, SLOT(close) );
175     ka = actionCollection()->addAction(KStandardAction::Quit, "quit", qApp, SLOT(closeAllWindows()));
176     ka->setIcon(QIcon::fromTheme("application-exit"));
177 
178     // ==== Time Menu ================
179     actionCollection()->addAction("time_to_now", this, SLOT(slotSetTimeToNow()))
180             << i18n("Set Time to &Now") << QKeySequence(Qt::CTRL + Qt::Key_E)
181             << QIcon::fromTheme("clock");
182 
183     actionCollection()->addAction("time_dialog", this, SLOT(slotSetTime()))
184             << i18nc("set Clock to New Time", "&Set Time...") << QKeySequence(Qt::CTRL + Qt::Key_S)
185             << QIcon::fromTheme("clock");
186 
187     ka = actionCollection()->add<KToggleAction>("clock_startstop")
188          << i18n("Stop &Clock")
189          << QIcon::fromTheme("media-playback-pause");
190     if (!StartClockRunning)
191         ka->toggle();
192     QObject::connect(ka, SIGNAL(triggered()), this, SLOT(slotToggleTimer()));
193 
194     // If we are started in --paused state make sure the icon reflects that now
195     if (StartClockRunning == false)
196     {
197         QAction *a = actionCollection()->action("clock_startstop");
198         if (a)
199             a->setIcon(QIcon::fromTheme("run-build-install-root"));
200     }
201 
202     QObject::connect(data()->clock(), &SimClock::clockToggled, [ = ](bool toggled)
203     {
204         QAction *a = actionCollection()->action("clock_startstop");
205         if (a)
206         {
207             a->setChecked(toggled);
208             // Many users forget to unpause KStars, so we are using run-build-install-root icon which is red
209             // and stands out from the rest of the icons so users are aware when KStars is paused visually
210             a->setIcon(toggled ? QIcon::fromTheme("run-build-install-root") : QIcon::fromTheme("media-playback-pause"));
211             a->setToolTip(toggled ? i18n("Resume Clock") : i18n("Stop Clock"));
212         }
213     });
214     //UpdateTime() if clock is stopped (so hidden objects get drawn)
215     QObject::connect(data()->clock(), SIGNAL(clockToggled(bool)), this, SLOT(updateTime()));
216     actionCollection()->addAction("time_step_forward", this, SLOT(slotStepForward()))
217             << i18n("Advance One Step Forward in Time")
218             << QIcon::fromTheme("media-skip-forward")
219             << QKeySequence(Qt::Key_Greater);
220     actionCollection()->addAction("time_step_backward", this, SLOT(slotStepBackward()))
221             << i18n("Advance One Step Backward in Time")
222             << QIcon::fromTheme("media-skip-backward")
223             << QKeySequence(Qt::Key_Less);
224 
225     // ==== Pointing Menu ================
226     actionCollection()->addAction("zenith", this, SLOT(slotPointFocus())) << i18n("&Zenith") << QKeySequence("Z");
227     actionCollection()->addAction("north", this, SLOT(slotPointFocus())) << i18n("&North") << QKeySequence("N");
228     actionCollection()->addAction("east", this, SLOT(slotPointFocus())) << i18n("&East") << QKeySequence("E");
229     actionCollection()->addAction("south", this, SLOT(slotPointFocus())) << i18n("&South") << QKeySequence("S");
230     actionCollection()->addAction("west", this, SLOT(slotPointFocus())) << i18n("&West") << QKeySequence("W");
231 
232     actionCollection()->addAction("find_object", this, SLOT(slotFind()))
233             << i18n("&Find Object...") << QIcon::fromTheme("edit-find")
234             << QKeySequence(Qt::CTRL + Qt::Key_F);
235     actionCollection()->addAction("track_object", this, SLOT(slotTrack()))
236             << i18n("Engage &Tracking")
237             << QIcon::fromTheme("object-locked")
238             << QKeySequence(Qt::CTRL + Qt::Key_T);
239     actionCollection()->addAction("manual_focus", this, SLOT(slotManualFocus()))
240             << i18n("Set Coordinates &Manually...") << QKeySequence(Qt::CTRL + Qt::Key_M);
241 
242     QAction *action;
243 
244     // ==== View Menu ================
245     action = actionCollection()->addAction(KStandardAction::ZoomIn, "zoom_in", map(), SLOT(slotZoomIn()));
246     action->setIcon(QIcon::fromTheme("zoom-in"));
247 
248     action = actionCollection()->addAction(KStandardAction::ZoomOut, "zoom_out", map(), SLOT(slotZoomOut()));
249     action->setIcon(QIcon::fromTheme("zoom-out"));
250 
251     actionCollection()->addAction("zoom_default", map(), SLOT(slotZoomDefault()))
252             << i18n("&Default Zoom") << QIcon::fromTheme("zoom-fit-best")
253             << QKeySequence(Qt::CTRL + Qt::Key_Z);
254     actionCollection()->addAction("zoom_set", this, SLOT(slotSetZoom()))
255             << i18n("&Zoom to Angular Size...")
256             << QIcon::fromTheme("zoom-original")
257             << QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Z);
258 
259     action = actionCollection()->addAction(KStandardAction::FullScreen, this, SLOT(slotFullScreen()));
260     action->setIcon(QIcon::fromTheme("view-fullscreen"));
261 
262     actionCollection()->addAction("coordsys", this, SLOT(slotCoordSys()))
263             << (Options::useAltAz() ? i18n("Switch to Star Globe View (Equatorial &Coordinates)") :
264                 i18n("Switch to Horizonal View (Horizontal &Coordinates)"))
265             << QKeySequence("Space");
266 
267     actionCollection()->addAction("toggle_terrain", this, SLOT(slotTerrain()))
268             << (Options::showTerrain() ? i18n("Hide Terrain") :
269                 i18n("Show Terrain"))
270             << QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_T);
271 
272     actionCollection()->addAction("project_lambert", this, SLOT(slotMapProjection()))
273             << i18n("&Lambert Azimuthal Equal-area") << QKeySequence("F5") << AddToGroup(projectionGroup)
274             << Checked(Options::projection() == Projector::Lambert);
275     actionCollection()->addAction("project_azequidistant", this, SLOT(slotMapProjection()))
276             << i18n("&Azimuthal Equidistant") << QKeySequence("F6") << AddToGroup(projectionGroup)
277             << Checked(Options::projection() == Projector::AzimuthalEquidistant);
278     actionCollection()->addAction("project_orthographic", this, SLOT(slotMapProjection()))
279             << i18n("&Orthographic") << QKeySequence("F7") << AddToGroup(projectionGroup)
280             << Checked(Options::projection() == Projector::Orthographic);
281     actionCollection()->addAction("project_equirectangular", this, SLOT(slotMapProjection()))
282             << i18n("&Equirectangular") << QKeySequence("F8") << AddToGroup(projectionGroup)
283             << Checked(Options::projection() == Projector::Equirectangular);
284     actionCollection()->addAction("project_stereographic", this, SLOT(slotMapProjection()))
285             << i18n("&Stereographic") << QKeySequence("F9") << AddToGroup(projectionGroup)
286             << Checked(Options::projection() == Projector::Stereographic);
287     actionCollection()->addAction("project_gnomonic", this, SLOT(slotMapProjection()))
288             << i18n("&Gnomonic") << QKeySequence("F10") << AddToGroup(projectionGroup)
289             << Checked(Options::projection() == Projector::Gnomonic);
290 
291     //Settings Menu:
292     //Info Boxes option actions
293     QAction *kaBoxes = actionCollection()->add<KToggleAction>("show_boxes")
294                        << i18nc("Show the information boxes", "Show &Info Boxes") << Checked(Options::showInfoBoxes());
295     connect(kaBoxes, SIGNAL(toggled(bool)), map(), SLOT(slotToggleInfoboxes(bool)));
296     kaBoxes->setChecked(Options::showInfoBoxes());
297 
298     ka = actionCollection()->add<KToggleAction>("show_time_box")
299          << i18nc("Show time-related info box", "Show &Time Box");
300     connect(kaBoxes, SIGNAL(toggled(bool)), ka, SLOT(setEnabled(bool)));
301     connect(ka, SIGNAL(toggled(bool)), map(), SLOT(slotToggleTimeBox(bool)));
302     ka->setChecked(Options::showTimeBox());
303     ka->setEnabled(Options::showInfoBoxes());
304 
305     ka = actionCollection()->add<KToggleAction>("show_focus_box")
306          << i18nc("Show focus-related info box", "Show &Focus Box");
307     connect(kaBoxes, SIGNAL(toggled(bool)), ka, SLOT(setEnabled(bool)));
308     connect(ka, SIGNAL(toggled(bool)), map(), SLOT(slotToggleFocusBox(bool)));
309     ka->setChecked(Options::showFocusBox());
310     ka->setEnabled(Options::showInfoBoxes());
311 
312     ka = actionCollection()->add<KToggleAction>("show_location_box")
313          << i18nc("Show location-related info box", "Show &Location Box");
314     connect(kaBoxes, SIGNAL(toggled(bool)), ka, SLOT(setEnabled(bool)));
315     connect(ka, SIGNAL(toggled(bool)), map(), SLOT(slotToggleGeoBox(bool)));
316     ka->setChecked(Options::showGeoBox());
317     ka->setEnabled(Options::showInfoBoxes());
318 
319     //Toolbar options
320     newToggleAction(actionCollection(), "show_mainToolBar", i18n("Show Main Toolbar"), toolBar("kstarsToolBar"),
321                     SLOT(setVisible(bool)));
322     newToggleAction(actionCollection(), "show_viewToolBar", i18n("Show View Toolbar"), toolBar("viewToolBar"),
323                     SLOT(setVisible(bool)));
324 
325     //Statusbar view options
326     newToggleAction(actionCollection(), "show_statusBar", i18n("Show Statusbar"), this, SLOT(slotShowGUIItem(bool)));
327     newToggleAction(actionCollection(), "show_sbAzAlt", i18n("Show Az/Alt Field"), this, SLOT(slotShowGUIItem(bool)));
328     newToggleAction(actionCollection(), "show_sbRADec", i18n("Show RA/Dec Field"), this, SLOT(slotShowGUIItem(bool)));
329     newToggleAction(actionCollection(), "show_sbJ2000RADec", i18n("Show J2000.0 RA/Dec Field"), this,
330                     SLOT(slotShowGUIItem(bool)));
331 
332 
333     populateThemes();
334 
335     //Color scheme actions.  These are added to the "colorschemes" KActionMenu.
336     colorActionMenu = actionCollection()->add<KActionMenu>("colorschemes");
337     colorActionMenu->setText(i18n("C&olor Schemes"));
338     addColorMenuItem(i18n("&Classic"), "cs_classic");
339     addColorMenuItem(i18n("&Star Chart"), "cs_chart");
340     addColorMenuItem(i18n("&Night Vision"), "cs_night");
341     addColorMenuItem(i18n("&Moonless Night"), "cs_moonless-night");
342 
343     //Add any user-defined color schemes:
344     //determine filename in local user KDE directory tree.
345     QFile file(KSPaths::locate(QStandardPaths::AppDataLocation, "colors.dat"));
346     if (file.exists() && file.open(QIODevice::ReadOnly))
347     {
348         QTextStream stream(&file);
349         while (!stream.atEnd())
350         {
351             QString line       = stream.readLine();
352             QString schemeName = line.left(line.indexOf(':'));
353             QString actionname = "cs_" + line.mid(line.indexOf(':') + 1, line.indexOf('.') - line.indexOf(':') - 1);
354             addColorMenuItem(i18n(schemeName.toLocal8Bit()), actionname.toLocal8Bit());
355         }
356         file.close();
357     }
358 
359     //Add FOV Symbol actions
360     fovActionMenu = actionCollection()->add<KActionMenu>("fovsymbols");
361     fovActionMenu->setText(i18n("&FOV Symbols"));
362     fovActionMenu->setDelayed(false);
363     fovActionMenu->setIcon(QIcon::fromTheme("crosshairs"));
364     FOVManager::readFOVs();
365     repopulateFOV();
366 
367     //Add HIPS Sources actions
368     hipsActionMenu = actionCollection()->add<KActionMenu>("hipssources");
369     hipsActionMenu->setText(i18n("HiPS All Sky Overlay"));
370     hipsActionMenu->setDelayed(false);
371     hipsActionMenu->setIcon(QIcon::fromTheme("view-preview"));
372     HIPSManager::Instance()->readSources();
373     repopulateHIPS();
374 
375     actionCollection()->addAction("geolocation", this, SLOT(slotGeoLocator()))
376             << i18nc("Location on Earth", "&Geographic...")
377             << QIcon::fromTheme("kstars_xplanet")
378             << QKeySequence(Qt::CTRL + Qt::Key_G);
379 
380     // Configure Notifications
381 #ifdef HAVE_NOTIFYCONFIG
382     KStandardAction::configureNotifications(this, SLOT(slotConfigureNotifications()), actionCollection());
383 #endif
384 
385     // Prepare the options dialog early for modules to connect signals
386     prepareOps();
387 
388     ka = actionCollection()->addAction(KStandardAction::Preferences, "configure", this, SLOT(slotViewOps()));
389     //I am not sure what icon preferences is supposed to be.
390     //ka->setIcon( QIcon::fromTheme(""));
391 
392     actionCollection()->addAction("startwizard", this, SLOT(slotWizard()))
393             << i18n("Startup Wizard...")
394             << QIcon::fromTheme("tools-wizard");
395 
396     // Manual data entry
397     actionCollection()->addAction("dso_catalog_gui", this, SLOT(slotDSOCatalogGUI()))
398             << i18n("Manage DSO Catalogs");
399 
400     // Updates actions
401     actionCollection()->addAction("update_comets", this, SLOT(slotUpdateComets()))
402             << i18n("Update Comets Orbital Elements");
403     actionCollection()->addAction("update_asteroids", this, SLOT(slotUpdateAsteroids()))
404             << i18n("Update Asteroids Orbital Elements");
405     actionCollection()->addAction("update_supernovae", this, SLOT(slotUpdateSupernovae()))
406             << i18n("Update Recent Supernovae Data");
407     actionCollection()->addAction("update_satellites", this, SLOT(slotUpdateSatellites()))
408             << i18n("Update Satellites Orbital Elements");
409 
410     //Tools Menu:
411     actionCollection()->addAction("astrocalculator", this, SLOT(slotCalculator()))
412             << i18n("Calculator")
413             << QIcon::fromTheme("accessories-calculator")
414             << QKeySequence(Qt::SHIFT + Qt::CTRL + Qt::Key_C);
415 
416     /* FIXME Enable once port to KF5 is complete for moonphasetool
417      actionCollection()->addAction("moonphasetool", this, SLOT(slotMoonPhaseTool()) )
418          << i18n("Moon Phase Calendar");
419     */
420 
421     actionCollection()->addAction("obslist", this, SLOT(slotObsList()))
422             << i18n("Observation Planner") << QKeySequence(Qt::CTRL + Qt::Key_L);
423 
424     actionCollection()->addAction("altitude_vs_time", this, SLOT(slotAVT()))
425             << i18n("Altitude vs. Time") << QKeySequence(Qt::CTRL + Qt::Key_A);
426 
427     actionCollection()->addAction("whats_up_tonight", this, SLOT(slotWUT()))
428             << i18n("What's up Tonight") << QKeySequence(Qt::CTRL + Qt::Key_U);
429 
430     //FIXME Port to QML2
431     //#if 0
432     actionCollection()->addAction("whats_interesting", this, SLOT(slotToggleWIView()))
433             << i18n("What's Interesting...") << QKeySequence(Qt::CTRL + Qt::Key_W);
434     //#endif
435 
436     actionCollection()->addAction("XPlanet", map(), SLOT(slotStartXplanetViewer()))
437             << i18n("XPlanet Solar System Simulator") << QKeySequence(Qt::CTRL + Qt::Key_X);
438 
439     actionCollection()->addAction("skycalendar", this, SLOT(slotCalendar())) << i18n("Sky Calendar");
440 
441 #ifdef HAVE_INDI
442     ka = actionCollection()->addAction("ekos", this, SLOT(slotEkos()))
443          << i18n("Ekos") << QKeySequence(Qt::CTRL + Qt::Key_K);
444     ka->setShortcutContext(Qt::ApplicationShortcut);
445 #endif
446 
447     //FIXME: implement glossary
448     //     ka = actionCollection()->addAction("glossary");
449     //     ka->setText( i18n("Glossary...") );
450     //     ka->setShortcuts( QKeySequence(Qt::CTRL+Qt::Key_K ) );
451     //     connect( ka, SIGNAL(triggered()), this, SLOT(slotGlossary()) );
452 
453     // 2017-09-17 Jasem: FIXME! Scripting does not work properly under non UNIX systems.
454     // It must be updated to use DBus session bus from Qt (like scheduler)
455 #ifndef Q_OS_WIN
456     actionCollection()->addAction("scriptbuilder", this, SLOT(slotScriptBuilder()))
457             << i18n("Script Builder") << QKeySequence(Qt::CTRL + Qt::Key_B);
458 #endif
459 
460     actionCollection()->addAction("solarsystem", this, SLOT(slotSolarSystem()))
461             << i18n("Solar System") << QKeySequence(Qt::CTRL + Qt::Key_Y);
462 
463     // Disabled until fixed later
464     actionCollection()->addAction("jmoontool", this, SLOT(slotJMoonTool()) )
465             << i18n("Jupiter's Moons")
466             << QKeySequence(Qt::CTRL + Qt::Key_J );
467 
468     actionCollection()->addAction("flagmanager", this, SLOT(slotFlagManager())) << i18n("Flags");
469 
470     actionCollection()->addAction("equipmentwriter", this, SLOT(slotEquipmentWriter()))
471             << i18n("List your &Equipment...") << QIcon::fromTheme("kstars") << QKeySequence(Qt::CTRL + Qt::Key_0);
472     actionCollection()->addAction("manageobserver", this, SLOT(slotObserverManager()))
473             << i18n("Manage Observer...") << QIcon::fromTheme("im-user") << QKeySequence(Qt::CTRL + Qt::Key_1);
474 
475     //TODO only enable it when finished
476     actionCollection()->addAction("artificialhorizon", this, SLOT(slotHorizonManager()))
477             << i18n("Artificial Horizon...");
478 
479     // ==== observation menu - execute ================
480     actionCollection()->addAction("execute", this, SLOT(slotExecute()))
481             << i18n("Execute the Session Plan...") << QKeySequence(Qt::CTRL + Qt::Key_2);
482 
483     // ==== observation menu - polaris hour angle ================
484     actionCollection()->addAction("polaris_hour_angle", this, SLOT(slotPolarisHourAngle()))
485             << i18n("Polaris Hour Angle...");
486 
487     // ==== devices Menu ================
488 #ifdef HAVE_INDI
489 #ifndef Q_OS_WIN
490 #if 0
491     actionCollection()->addAction("telescope_wizard", this, SLOT(slotTelescopeWizard()))
492             << i18n("Telescope Wizard...")
493             << QIcon::fromTheme("tools-wizard");
494 #endif
495 #endif
496     actionCollection()->addAction("device_manager", this, SLOT(slotINDIDriver()))
497             << i18n("Device Manager...")
498             << QIcon::fromTheme("network-server")
499             << QKeySequence(Qt::SHIFT + Qt::META + Qt::Key_D);
500     actionCollection()->addAction("custom_drivers", DriverManager::Instance(), SLOT(showCustomDrivers()))
501             << i18n("Custom Drivers...")
502             << QIcon::fromTheme("address-book-new");
503     ka = actionCollection()->addAction("indi_cpl", this, SLOT(slotINDIPanel()))
504          << i18n("INDI Control Panel...")
505          << QKeySequence(Qt::CTRL + Qt::Key_I);
506     ka->setShortcutContext(Qt::ApplicationShortcut);
507     ka->setEnabled(false);
508 #else
509     //FIXME need to disable/hide devices submenu in the tools menu. It is created from the kstarsui.rc file
510     //but I don't know how to hide/disable it yet. menuBar()->findChildren<QMenu *>() does not return any children that I can
511     //iterate over. Anyway to resolve this?
512 #endif
513 
514     //Help Menu:
515     ka = actionCollection()->addAction(KStandardAction::TipofDay, "help_tipofday", this, SLOT(slotTipOfDay()));
516     ka->setWhatsThis(i18n("Displays the Tip of the Day"));
517     ka->setIcon(QIcon::fromTheme("help-hint"));
518     //	KStandardAction::help(this, SLOT(appHelpActivated()), actionCollection(), "help_contents" );
519 
520     //Add timestep widget for toolbar
521     m_TimeStepBox = new TimeStepBox(toolBar("kstarsToolBar"));
522     // Add a tool tip to TimeStep describing the weird nature of time steps
523     QString TSBToolTip = i18nc("Tooltip describing the nature of the time step control",
524                                "Use this to set the rate at which time in the simulation flows.\nFor time step \'X\' "
525                                "up to 10 minutes, time passes at the rate of \'X\' per second.\nFor time steps larger "
526                                "than 10 minutes, frames are displayed at an interval of \'X\'.");
527     m_TimeStepBox->setToolTip(TSBToolTip);
528     m_TimeStepBox->tsbox()->setToolTip(TSBToolTip);
529     QWidgetAction *wa = new QWidgetAction(this);
530     wa->setDefaultWidget(m_TimeStepBox);
531 
532     // Add actions for the timestep widget's functions
533     actionCollection()->addAction("timestep_control", wa) << i18n("Time step control");
534     const auto unitbox = m_TimeStepBox->unitbox();
535     ka = actionCollection()->addAction("timestep_increase_units", unitbox->increaseUnitsAction());
536     ka->setShortcut(QKeySequence(Qt::Key_Plus));
537     ka = actionCollection()->addAction("timestep_decrease_units", unitbox->decreaseUnitsAction());
538     ka->setShortcut(QKeySequence(Qt::Key_Underscore));
539 
540     // ==== viewToolBar actions ================
541     actionCollection()->add<KToggleAction>("show_stars", this, SLOT(slotViewToolBar()))
542             << i18nc("Toggle Stars in the display", "Stars")
543             << QIcon::fromTheme("kstars_stars")
544             << ToolTip(i18n("Toggle stars"));
545     actionCollection()->add<KToggleAction>("show_deepsky", this, SLOT(slotViewToolBar()))
546             << i18nc("Toggle Deep Sky Objects in the display", "Deep Sky")
547             << QIcon::fromTheme("kstars_deepsky")
548             << ToolTip(i18n("Toggle deep sky objects"));
549     actionCollection()->add<KToggleAction>("show_planets", this, SLOT(slotViewToolBar()))
550             << i18nc("Toggle Solar System objects in the display", "Solar System")
551             << QIcon::fromTheme("kstars_planets")
552             << ToolTip(i18n("Toggle Solar system objects"));
553     actionCollection()->add<KToggleAction>("show_clines", this, SLOT(slotViewToolBar()))
554             << i18nc("Toggle Constellation Lines in the display", "Const. Lines")
555             << QIcon::fromTheme("kstars_clines")
556             << ToolTip(i18n("Toggle constellation lines"));
557     actionCollection()->add<KToggleAction>("show_cnames", this, SLOT(slotViewToolBar()))
558             << i18nc("Toggle Constellation Names in the display", "Const. Names")
559             << QIcon::fromTheme("kstars_cnames")
560             << ToolTip(i18n("Toggle constellation names"));
561     actionCollection()->add<KToggleAction>("show_cbounds", this, SLOT(slotViewToolBar()))
562             << i18nc("Toggle Constellation Boundaries in the display", "C. Boundaries")
563             << QIcon::fromTheme("kstars_cbound")
564             << ToolTip(i18n("Toggle constellation boundaries"));
565     actionCollection()->add<KToggleAction>("show_constellationart", this, SLOT(slotViewToolBar()))
566             << xi18nc("Toggle Constellation Art in the display", "C. Art (BETA)")
567             << QIcon::fromTheme("kstars_constellationart")
568             << ToolTip(xi18n("Toggle constellation art (BETA)"));
569     actionCollection()->add<KToggleAction>("show_mw", this, SLOT(slotViewToolBar()))
570             << i18nc("Toggle Milky Way in the display", "Milky Way")
571             << QIcon::fromTheme("kstars_mw")
572             << ToolTip(i18n("Toggle milky way"));
573     actionCollection()->add<KToggleAction>("show_equatorial_grid", this, SLOT(slotViewToolBar()))
574             << i18nc("Toggle Equatorial Coordinate Grid in the display", "Equatorial coord. grid")
575             << QIcon::fromTheme("kstars_grid")
576             << ToolTip(i18n("Toggle equatorial coordinate grid"));
577     actionCollection()->add<KToggleAction>("show_horizontal_grid", this, SLOT(slotViewToolBar()))
578             << i18nc("Toggle Horizontal Coordinate Grid in the display", "Horizontal coord. grid")
579             << QIcon::fromTheme("kstars_hgrid")
580             << ToolTip(i18n("Toggle horizontal coordinate grid"));
581     actionCollection()->add<KToggleAction>("show_horizon", this, SLOT(slotViewToolBar()))
582             << i18nc("Toggle the opaque fill of the ground polygon in the display", "Ground")
583             << QIcon::fromTheme("kstars_horizon")
584             << ToolTip(i18n("Toggle opaque ground"));
585     actionCollection()->add<KToggleAction>("show_flags", this, SLOT(slotViewToolBar()))
586             << i18nc("Toggle flags in the display", "Flags")
587             << QIcon::fromTheme("kstars_flag")
588             << ToolTip(i18n("Toggle flags"));
589     actionCollection()->add<KToggleAction>("show_satellites", this, SLOT(slotViewToolBar()))
590             << i18nc("Toggle satellites in the display", "Satellites")
591             << QIcon::fromTheme("kstars_satellites")
592             << ToolTip(i18n("Toggle satellites"));
593     actionCollection()->add<KToggleAction>("show_supernovae", this, SLOT(slotViewToolBar()))
594             << i18nc("Toggle supernovae in the display", "Supernovae")
595             << QIcon::fromTheme("kstars_supernovae")
596             << ToolTip(i18n("Toggle supernovae"));
597     actionCollection()->add<KToggleAction>("show_whatsinteresting", this, SLOT(slotToggleWIView()))
598             << i18nc("Toggle What's Interesting", "What's Interesting")
599             << QIcon::fromTheme("view-list-details")
600             << ToolTip(i18n("Toggle What's Interesting"));
601 
602 #ifdef HAVE_INDI
603     // ==== INDIToolBar actions ================
604     actionCollection()->add<KToggleAction>("show_ekos", this, SLOT(slotINDIToolBar()))
605             << i18nc("Toggle Ekos in the display", "Ekos")
606             << QIcon::fromTheme("kstars_ekos")
607             << ToolTip(i18n("Toggle Ekos"));
608     ka = actionCollection()->add<KToggleAction>("show_control_panel", this, SLOT(slotINDIToolBar()))
609          << i18nc("Toggle the INDI Control Panel in the display", "INDI Control Panel")
610          << QIcon::fromTheme("kstars_indi")
611          << ToolTip(i18n("Toggle INDI Control Panel"));
612     ka->setEnabled(false);
613     ka = actionCollection()->add<KToggleAction>("show_fits_viewer", this, SLOT(slotINDIToolBar()))
614          << i18nc("Toggle the FITS Viewer in the display", "FITS Viewer")
615          << QIcon::fromTheme("kstars_fitsviewer")
616          << ToolTip(i18n("Toggle FITS Viewer"));
617     ka->setEnabled(false);
618 
619     ka = actionCollection()->add<KToggleAction>("show_sensor_fov", this, SLOT(slotINDIToolBar()))
620          << i18nc("Toggle the sensor Field of View", "Sensor FOV")
621          << QIcon::fromTheme("archive-extract")
622          << ToolTip(i18n("Toggle Sensor FOV"));
623     ka->setEnabled(false);
624     ka->setChecked(Options::showSensorFOV());
625 
626     ka = actionCollection()->add<KToggleAction>("show_mount_box", this, SLOT(slotINDIToolBar()))
627          << i18nc("Toggle the Mount Control Panel", "Mount Control")
628          << QIcon::fromTheme("draw-text")
629          << ToolTip(i18n("Toggle Mount Control Panel"));
630     telescopeGroup->addAction(ka);
631 
632     ka = actionCollection()->add<KToggleAction>("lock_telescope", this, SLOT(slotINDIToolBar()))
633          << i18nc("Toggle the telescope center lock in display", "Center Telescope")
634          << QIcon::fromTheme("center_telescope", QIcon(":/icons/center_telescope.svg"))
635          << ToolTip(i18n("Toggle Lock Telescope Center"));
636     telescopeGroup->addAction(ka);
637 
638     ka = actionCollection()->add<KToggleAction>("telescope_track", this, SLOT(slotINDITelescopeTrack()))
639          << i18n("Toggle Telescope Tracking")
640          << QIcon::fromTheme("object-locked");
641     telescopeGroup->addAction(ka);
642     ka = actionCollection()->addAction("telescope_slew", this, SLOT(slotINDITelescopeSlew()))
643          << i18n("Slew telescope to the focused object")
644          << QIcon::fromTheme("object-rotate-right");
645     telescopeGroup->addAction(ka);
646     ka = actionCollection()->addAction("telescope_sync", this, SLOT(slotINDITelescopeSync()))
647          << i18n("Sync telescope to the focused object")
648          << QIcon::fromTheme("media-record");
649     telescopeGroup->addAction(ka);
650     ka = actionCollection()->addAction("telescope_abort", this, SLOT(slotINDITelescopeAbort()))
651          << i18n("Abort telescope motions")
652          << QIcon::fromTheme("process-stop");
653     ka->setShortcutContext(Qt::ApplicationShortcut);
654     telescopeGroup->addAction(ka);
655     ka = actionCollection()->addAction("telescope_park", this, SLOT(slotINDITelescopePark()))
656          << i18n("Park telescope")
657          << QIcon::fromTheme("flag-red");
658     telescopeGroup->addAction(ka);
659     ka = actionCollection()->addAction("telescope_unpark", this, SLOT(slotINDITelescopeUnpark()))
660          << i18n("Unpark telescope")
661          << QIcon::fromTheme("flag-green");
662     ka->setShortcutContext(Qt::ApplicationShortcut);
663     telescopeGroup->addAction(ka);
664 
665     actionCollection()->addAction("telescope_slew_mouse", this, SLOT(slotINDITelescopeSlewMousePointer()))
666             << i18n("Slew the telescope to the mouse pointer position");
667 
668     actionCollection()->addAction("telescope_sync_mouse", this, SLOT(slotINDITelescopeSyncMousePointer()))
669             << i18n("Sync the telescope to the mouse pointer position");
670 
671     // Disable all telescope actions by default
672     telescopeGroup->setEnabled(false);
673 
674     // Dome Actions
675     ka = actionCollection()->addAction("dome_park", this, SLOT(slotINDIDomePark()))
676          << i18n("Park dome")
677          << QIcon::fromTheme("dome-park", QIcon(":/icons/dome-park.svg"));
678     domeGroup->addAction(ka);
679     ka = actionCollection()->addAction("dome_unpark", this, SLOT(slotINDIDomeUnpark()))
680          << i18n("Unpark dome")
681          << QIcon::fromTheme("dome-unpark", QIcon(":/icons/dome-unpark.svg"));
682     ka->setShortcutContext(Qt::ApplicationShortcut);
683     domeGroup->addAction(ka);
684 
685     domeGroup->setEnabled(false);
686 #endif
687 }
688 
repopulateFOV()689 void KStars::repopulateFOV()
690 {
691     // Read list of all FOVs
692     //qDeleteAll( data()->availFOVs );
693     data()->availFOVs = FOVManager::getFOVs();
694     data()->syncFOV();
695 
696     // Iterate through FOVs
697     fovActionMenu->menu()->clear();
698     foreach (FOV *fov, data()->availFOVs)
699     {
700         KToggleAction *kta = actionCollection()->add<KToggleAction>(fov->name());
701         kta->setText(fov->name());
702         if (Options::fOVNames().contains(fov->name()))
703         {
704             kta->setChecked(true);
705         }
706 
707         fovActionMenu->addAction(kta);
708         connect(kta, SIGNAL(toggled(bool)), this, SLOT(slotTargetSymbol(bool)));
709     }
710     // Add menu bottom
711     QAction *ka = actionCollection()->addAction("edit_fov", this, SLOT(slotFOVEdit())) << i18n("Edit FOV Symbols...");
712     fovActionMenu->addSeparator();
713     fovActionMenu->addAction(ka);
714 }
715 
repopulateHIPS()716 void KStars::repopulateHIPS()
717 {
718     // Iterate through actions
719     hipsActionMenu->menu()->clear();
720     // Remove all actions
721     QList<QAction*> actions = hipsGroup->actions();
722 
723     for (auto &action : actions)
724         hipsGroup->removeAction(action);
725 
726     QAction *ka = actionCollection()->addAction(i18n("None"), this, SLOT(slotHIPSSource()))
727                   << i18n("None") << AddToGroup(hipsGroup)
728                   << Checked(Options::hIPSSource() == "None");
729 
730     hipsActionMenu->addAction(ka);
731     hipsActionMenu->addSeparator();
732 
733     for (QMap<QString, QString> source : HIPSManager::Instance()->getHIPSSources())
734     {
735         QString title = source.value("obs_title");
736 
737         QAction *ka = actionCollection()->addAction(title, this, SLOT(slotHIPSSource()))
738                       << title << AddToGroup(hipsGroup)
739                       << Checked(Options::hIPSSource() == title);
740 
741         hipsActionMenu->addAction(ka);
742     }
743 
744     // Hips settings
745     ka = actionCollection()->addAction("hipssettings", HIPSManager::Instance(),
746                                        SLOT(showSettings())) << i18n("HiPS Settings...");
747     hipsActionMenu->addSeparator();
748     hipsActionMenu->addAction(ka);
749 }
750 
initStatusBar()751 void KStars::initStatusBar()
752 {
753     statusBar()->showMessage(i18n(" Welcome to KStars "));
754 
755     QString s = "000d 00m 00s,   +00d 00\' 00\""; //only need this to set the width
756     if (Options::showAltAzField())
757     {
758         AltAzField.setText(s);
759         statusBar()->insertPermanentWidget(0, &AltAzField);
760     }
761 
762     if (Options::showRADecField())
763     {
764         RADecField.setText(s);
765         statusBar()->insertPermanentWidget(1, &RADecField);
766     }
767 
768     if (Options::showJ2000RADecField())
769     {
770         J2000RADecField.setText(s);
771         statusBar()->insertPermanentWidget(1, &J2000RADecField);
772     }
773 
774     if (!Options::showStatusBar())
775         statusBar()->hide();
776 }
777 
datainitFinished()778 void KStars::datainitFinished()
779 {
780     //Time-related connections
781     connect(data()->clock(), SIGNAL(timeAdvanced()), this, SLOT(updateTime()));
782     connect(data()->clock(), SIGNAL(timeChanged()), this, SLOT(updateTime()));
783 
784     //Add GUI elements to main window
785     buildGUI();
786 
787     connect(data()->clock(), SIGNAL(scaleChanged(float)), map(), SLOT(slotClockSlewing()));
788 
789     connect(data(), SIGNAL(skyUpdate(bool)), map(), SLOT(forceUpdateNow()));
790     connect(m_TimeStepBox, SIGNAL(scaleChanged(float)), data(), SLOT(setTimeDirection(float)));
791     connect(m_TimeStepBox, SIGNAL(scaleChanged(float)), data()->clock(), SLOT(setClockScale(float)));
792     connect(m_TimeStepBox, SIGNAL(scaleChanged(float)), map(), SLOT(setFocus()));
793 
794     //m_equipmentWriter = new EquipmentWriter();
795     //m_observerAdd = new ObserverAdd;
796 
797     //Do not start the clock if "--paused" specified on the cmd line
798     if (StartClockRunning)
799     {
800         // The initial time is set when KStars is first executed
801         // but until all data is loaded, some time elapsed already so we need to synchronize if no Start Date string
802         // was supplied to KStars
803         if (StartDateString.isEmpty())
804             data()->changeDateTime(KStarsDateTime::currentDateTimeUtc());
805 
806         data()->clock()->start();
807     }
808 
809     // Connect cache function for Find dialog
810     connect(data(), SIGNAL(clearCache()), this, SLOT(clearCachedFindDialog()));
811 
812     //Propagate config settings
813     applyConfig(false);
814 
815     //show the window.  must be before kswizard and messageboxes
816     show();
817 
818     //Initialize focus
819     initFocus();
820 
821     data()->setFullTimeUpdate();
822     updateTime();
823 
824     // Initial State
825     qCDebug(KSTARS) << "Date/Time is:" << data()->clock()->utc().toString();
826     qCDebug(KSTARS) << "Location:" << data()->geo()->fullName();
827     qCDebug(KSTARS) << "TZ0:" << data()->geo()->TZ0() << "TZ:" << data()->geo()->TZ();
828 
829     KSTheme::Manager::instance()->setCurrentTheme(Options::currentTheme());
830 
831     //If this is the first startup, show the wizard
832     if (Options::runStartupWizard())
833     {
834         slotWizard();
835     }
836 
837     //Show TotD
838     KTipDialog::showTip(this, "kstars/tips");
839 
840     // Update comets and asteroids if enabled.
841     if (Options::orbitalElementsAutoUpdate())
842     {
843         slotUpdateComets(true);
844         slotUpdateAsteroids(true);
845     }
846 
847 #ifdef HAVE_INDI
848     Ekos::Manager::Instance()->initialize();
849 #endif
850 }
851 
initFocus()852 void KStars::initFocus()
853 {
854     //Case 1: tracking on an object
855     if (Options::isTracking() && Options::focusObject() != i18n("nothing"))
856     {
857         SkyObject *oFocus;
858         if (Options::focusObject() == i18n("star"))
859         {
860             SkyPoint p(Options::focusRA(), Options::focusDec());
861             double maxrad = 1.0;
862 
863             oFocus = data()->skyComposite()->starNearest(&p, maxrad);
864         }
865         else
866         {
867             oFocus = data()->objectNamed(Options::focusObject());
868         }
869 
870         if (oFocus)
871         {
872             map()->setFocusObject(oFocus);
873             map()->setClickedObject(oFocus);
874             map()->setFocusPoint(oFocus);
875         }
876         else
877         {
878             qWarning() << "Cannot center on " << Options::focusObject() << ": no object found.";
879         }
880 
881         //Case 2: not tracking, and using Alt/Az coords.  Set focus point using
882         //FocusRA as the Azimuth, and FocusDec as the Altitude
883     }
884     else if (!Options::isTracking() && Options::useAltAz())
885     {
886         SkyPoint pFocus;
887         pFocus.setAz(Options::focusRA());
888         pFocus.setAlt(Options::focusDec());
889         pFocus.HorizontalToEquatorial(data()->lst(), data()->geo()->lat());
890         map()->setFocusPoint(&pFocus);
891 
892         //Default: set focus point using FocusRA as the RA and
893         //FocusDec as the Dec
894     }
895     else
896     {
897         SkyPoint pFocus(Options::focusRA(), Options::focusDec());
898         pFocus.EquatorialToHorizontal(data()->lst(), data()->geo()->lat());
899         map()->setFocusPoint(&pFocus);
900     }
901     data()->setSnapNextFocus();
902     map()->setDestination(*map()->focusPoint());
903     map()->setFocus(map()->destination());
904 
905     map()->showFocusCoords();
906 
907     //Check whether initial position is below the horizon.
908     if (Options::useAltAz() && Options::showGround() && map()->focus()->alt().Degrees() <= SkyPoint::altCrit)
909     {
910         QString caption = i18n("Initial Position is Below Horizon");
911         QString message =
912             i18n("The initial position is below the horizon.\nWould you like to reset to the default position?");
913         if (KMessageBox::warningYesNo(this, message, caption, KGuiItem(i18n("Reset Position")),
914                                       KGuiItem(i18n("Do Not Reset")), "dag_start_below_horiz") == KMessageBox::Yes)
915         {
916             map()->setClickedObject(nullptr);
917             map()->setFocusObject(nullptr);
918             Options::setIsTracking(false);
919 
920             data()->setSnapNextFocus(true);
921 
922             SkyPoint DefaultFocus;
923             DefaultFocus.setAz(180.0);
924             DefaultFocus.setAlt(45.0);
925             DefaultFocus.HorizontalToEquatorial(data()->lst(), data()->geo()->lat());
926             map()->setDestination(DefaultFocus);
927         }
928     }
929 
930     //If there is a focusObject() and it is a SS body, add a temporary Trail
931     if (map()->focusObject() && map()->focusObject()->isSolarSystem() && Options::useAutoTrail())
932     {
933         ((KSPlanetBase *)map()->focusObject())->addToTrail();
934         data()->temporaryTrail = true;
935     }
936 }
937 
buildGUI()938 void KStars::buildGUI()
939 {
940     //create the texture manager
941     TextureManager::Create();
942     //create the skymap
943     m_SkyMap = SkyMap::Create();
944     connect(m_SkyMap, SIGNAL(mousePointChanged(SkyPoint*)), SLOT(slotShowPositionBar(SkyPoint*)));
945     connect(m_SkyMap, SIGNAL(zoomChanged()), SLOT(slotZoomChanged()));
946     setCentralWidget(m_SkyMap);
947 
948     //Initialize menus, toolbars, and statusbars
949     initStatusBar();
950     initActions();
951 
952     // Setup GUI from the settings file
953     // UI tests provide the default settings file from the resources explicitly file to render UI properly
954     setupGUI(StandardWindowOptions(Default), m_KStarsUIResource);
955 
956     //get focus of keyboard and mouse actions (for example zoom in with +)
957     map()->QWidget::setFocus();
958     resize(Options::windowWidth(), Options::windowHeight());
959 
960     // check zoom in/out buttons
961     if (Options::zoomFactor() >= MAXZOOM)
962         actionCollection()->action("zoom_in")->setEnabled(false);
963     if (Options::zoomFactor() <= MINZOOM)
964         actionCollection()->action("zoom_out")->setEnabled(false);
965 }
966 
populateThemes()967 void KStars::populateThemes()
968 {
969     KSTheme::Manager::instance()->setThemeMenuAction(new QMenu(i18n("&Themes"), this));
970     KSTheme::Manager::instance()->registerThemeActions(this);
971 
972     connect(KSTheme::Manager::instance(), SIGNAL(signalThemeChanged()), this, SLOT(slotThemeChanged()));
973 }
974 
slotThemeChanged()975 void KStars::slotThemeChanged()
976 {
977     Options::setCurrentTheme(KSTheme::Manager::instance()->currentThemeName());
978 }
979