diff options
author | Alexander V. Wolf <alex.v.wolf@gmail.com> | 2022-05-22 17:30:24 +0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-22 17:30:24 +0700 |
commit | fa2c4a8e78b742230a9ecae64b7eaa65b832841c (patch) | |
tree | fec9bb697155b457e38fc502252bec348dbab407 | |
parent | 56c1d54f6e15946c69b6c5d333632562b9ddc967 (diff) |
Added visualisation Earth umbra and penumbra for satellites (#2451)
-rw-r--r-- | guide/pictures/satellites_plugin_configuration.jpg | bin | 0 -> 136349 bytes | |||
-rw-r--r-- | guide/pictures/satellites_plugin_configuration.png | bin | 102757 -> 0 bytes | |||
-rw-r--r-- | guide/plg_catalogs.tex | 19 | ||||
-rw-r--r-- | plugins/Satellites/src/Satellites.cpp | 183 | ||||
-rw-r--r-- | plugins/Satellites/src/Satellites.hpp | 100 | ||||
-rw-r--r-- | plugins/Satellites/src/gui/SatellitesDialog.cpp | 84 | ||||
-rw-r--r-- | plugins/Satellites/src/gui/SatellitesDialog.hpp | 2 | ||||
-rw-r--r-- | plugins/Satellites/src/gui/satellitesDialog.ui | 458 |
8 files changed, 582 insertions, 264 deletions
diff --git a/guide/pictures/satellites_plugin_configuration.jpg b/guide/pictures/satellites_plugin_configuration.jpg Binary files differnew file mode 100644 index 0000000000..bb9c82fcf0 --- /dev/null +++ b/guide/pictures/satellites_plugin_configuration.jpg diff --git a/guide/pictures/satellites_plugin_configuration.png b/guide/pictures/satellites_plugin_configuration.png Binary files differdeleted file mode 100644 index 163e1b4bbf..0000000000 --- a/guide/pictures/satellites_plugin_configuration.png +++ /dev/null diff --git a/guide/plg_catalogs.tex b/guide/plg_catalogs.tex index bbf251eebf..848dd766b2 100644 --- a/guide/plg_catalogs.tex +++ b/guide/plg_catalogs.tex @@ -1245,17 +1245,28 @@ online and are regularly updated. The plugin downloads the lists prepared by \url{https://celestrak.com} to keep itself up-to-date, but the users can specify other sources online or load updates from local files. -If enabled (see +If the plugin has been enabled (see section~\ref{sec:Plugins:EnablingPlugins}), just click on the Satellite button \guibutton{0.6}{bt_hint.png} on the bottom -toolbar to display markers for the satellites. +toolbar to display markers for the satellites, or use right click to call the GUI. -It should now be possible to search for artificial satellites using +You can search for artificial satellites using the regular search dialog (\key{F3}). Note that at any given time, most Satellites will be below the horizon. +Satellites can be either shown as white dots of appropriate brightness +similar to moving stars (just like they appear to the naked eye), or +as satellite-shaped markers (icons). Especially this latter view shows +the huge number of satellites in orbit, most of which are invisible to +the unaided eye. + +You can display \newFeature{0.22.2} circles representing the Earth's +shadow (penumbra and umbra, defined just like for Lunar eclipses, see +section~\ref{sec:Eclipses:lunar}), at the distance of the currently +selected satellite, or at a fixed distance from Earth's surface. + \begin{figure}[htbp] -\centering\includegraphics[width=0.8\textwidth]{satellites_plugin_configuration.png} +\centering\includegraphics[width=0.8\textwidth]{satellites_plugin_configuration.jpg} \caption{Configuration of the Satellites plugin.} \label{fig:plugins:Satellites:Configuration} \end{figure} diff --git a/plugins/Satellites/src/Satellites.cpp b/plugins/Satellites/src/Satellites.cpp index d72e2fe804..6f1edbcf1f 100644 --- a/plugins/Satellites/src/Satellites.cpp +++ b/plugins/Satellites/src/Satellites.cpp @@ -98,6 +98,13 @@ Satellites::Satellites() , autoAddEnabled(false) , autoRemoveEnabled(false) , updateFrequencyHours(0) + , flagUmbraVisible(false) + , flagUmbraAtFixedDistance(false) + , umbraColor(1.0f, 0.0f, 0.0f) + , umbraDistance(1000.0) + , flagPenumbraVisible(false) + , penumbraColor(1.0f, 0.0f, 0.0f) + , earthShadowEnlargementDanjon(false) #if(SATELLITES_PLUGIN_IRIDIUM == 1) , iridiumFlaresPredictionDepth(7) #endif @@ -110,6 +117,7 @@ void Satellites::deinit() { Satellite::hintTexture.clear(); texPointer.clear(); + texCross.clear(); } Satellites::~Satellites() @@ -149,6 +157,7 @@ void Satellites::init() // Load and find resources used in the plugin texPointer = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/pointeur5.png"); + texCross = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/cross.png"); Satellite::hintTexture = StelApp::getInstance().getTextureManager().createTexture(":/satellites/hint.png"); // key bindings and other actions @@ -210,7 +219,9 @@ void Satellites::init() connect(updateTimer, SIGNAL(timeout()), this, SLOT(checkForUpdate())); updateTimer->start(); - earth = GETSTELMODULE(SolarSystem)->getEarth(); + SolarSystem* ssystem = GETSTELMODULE(SolarSystem); + earth = ssystem->getEarth(); + sun = ssystem->getSun(); GETSTELMODULE(StelObjectMgr)->registerStelObjectMgr(this); // Handle changes to the observer location or wide range of dates: @@ -218,6 +229,7 @@ void Satellites::init() connect(core, SIGNAL(locationChanged(StelLocation)), this, SLOT(updateObserverLocation(StelLocation))); connect(core, SIGNAL(configurationDataSaved()), this, SLOT(saveSettings())); connect(&StelApp::getInstance(), SIGNAL(languageChanged()), this, SLOT(translateData())); + connect(ssystem, SIGNAL(earthShadowEnlargementDanjonChanged(bool)), this, SLOT(updateEarthShadowEnlargementFlag(bool))); bindingGroups(); } @@ -638,6 +650,12 @@ void Satellites::restoreDefaultSettings() conf->setValue("orbit_segment_duration", 20); conf->setValue("valid_epoch_age", 30); conf->setValue("iconic_mode_enabled", false); + conf->setValue("umbra_flag", false); + conf->setValue("umbra_fixed_distance_flag", false); + conf->setValue("umbra_color", "1.0,0.0,0.0"); + conf->setValue("umbra_fixed_distance", 1000.0); + conf->setValue("penumbra_flag", false); + conf->setValue("penumbra_color", "1.0,0.0,0.0"); conf->endGroup(); // saveTleSources() opens it for itself @@ -796,6 +814,14 @@ void Satellites::loadSettings() Satellite::timeRateLimit = conf->value("time_rate_limit", 1.0).toDouble(); Satellite::tleEpochAge = conf->value("valid_epoch_age", 30).toInt(); + // umbra/penumbra + setFlagUmbraVisible(conf->value("umbra_flag", false).toBool()); + setFlagUmbraAtFixedDistance(conf->value("umbra_fixed_distance_flag", false).toBool()); + setUmbraColor(Vec3f(conf->value("umbra_color", "1.0,0.0,0.0").toString())); + setUmbraDistance(conf->value("umbra_fixed_distance", 1000.0).toDouble()); + setFlagPenumbraVisible(conf->value("penumbra_flag", false).toBool()); + setPenumbraColor(Vec3f(conf->value("penumbra_color", "1.0,0.0,0.0").toString())); + // iconic mode setFlagIconicMode(conf->value("iconic_mode_enabled", false).toBool()); setFlagHideInvisible(conf->value("hide_invisible_satellites", false).toBool()); @@ -830,6 +856,14 @@ void Satellites::saveSettingsToConfig() conf->setValue("valid_epoch_age", Satellite::tleEpochAge); + // umbra/penumbra + conf->setValue("umbra_flag", getFlagUmbraVisible()); + conf->setValue("umbra_fixed_distance_flag", getFlagUmbraAtFixedDistance()); + conf->setValue("umbra_color", getUmbraColor().toStr()); + conf->setValue("umbra_fixed_distance", getUmbraDistance()); + conf->setValue("penumbra_flag", getFlagPenumbraVisible()); + conf->setValue("penumbra_color", getPenumbraColor().toStr()); + // iconic mode conf->setValue("iconic_mode_enabled", getFlagIconicMode()); conf->setValue("hide_invisible_satellites", getFlagHideInvisible()); @@ -840,7 +874,7 @@ void Satellites::saveSettingsToConfig() saveTleSources(updateUrls); } -Vec3f Satellites::getInvisibleSatelliteColor() const +Vec3f Satellites::getInvisibleSatelliteColor() { return Satellite::invisibleSatelliteColor; } @@ -851,7 +885,7 @@ void Satellites::setInvisibleSatelliteColor(const Vec3f &c) emit invisibleSatelliteColorChanged(c); } -Vec3f Satellites::getTransitSatelliteColor() const +Vec3f Satellites::getTransitSatelliteColor() { return Satellite::transitSatelliteColor; } @@ -1388,7 +1422,7 @@ void Satellites::saveTleSources(const QStringList& urls) conf->endGroup(); } -bool Satellites::getFlagLabelsVisible() const +bool Satellites::getFlagLabelsVisible() { return Satellite::showLabels; } @@ -1423,12 +1457,12 @@ void Satellites::setAutoRemoveEnabled(bool enabled) } } -bool Satellites::getFlagIconicMode() const +bool Satellites::getFlagIconicMode() { return Satellite::iconicModeFlag; } -bool Satellites::getFlagHideInvisible() const +bool Satellites::getFlagHideInvisible() { return Satellite::hideInvisibleSatellitesFlag; } @@ -1474,6 +1508,55 @@ void Satellites::setFlagLabelsVisible(bool b) } } +void Satellites::setFlagUmbraVisible(bool b) +{ + if (flagUmbraVisible != b) + { + flagUmbraVisible = b; + emit settingsChanged(); // GZ IS THIS REQUIRED/USEFUL?? + emit flagUmbraVisibleChanged(b); + } +} + +void Satellites::setFlagUmbraAtFixedDistance(bool b) +{ + if (flagUmbraAtFixedDistance != b) + { + flagUmbraAtFixedDistance = b; + emit settingsChanged(); // GZ IS THIS REQUIRED/USEFUL?? + emit flagUmbraAtFixedDistanceChanged(b); + } +} + +void Satellites::setUmbraColor(const Vec3f &c) +{ + umbraColor = c; + emit umbraColorChanged(c); +} + +void Satellites::setUmbraDistance(double d) +{ + umbraDistance = d; + emit umbraDistanceChanged(d); +} + +void Satellites::setFlagPenumbraVisible(bool b) +{ + if (flagPenumbraVisible != b) + { + flagPenumbraVisible = b; + emit settingsChanged(); // GZ IS THIS REQUIRED/USEFUL?? + emit flagPenumbraVisibleChanged(b); + } +} + +void Satellites::setPenumbraColor(const Vec3f &c) +{ + penumbraColor = c; + emit penumbraColorChanged(c); +} + + void Satellites::setLabelFontSize(int size) { if (labelFont.pixelSize() != size) @@ -1731,7 +1814,7 @@ void Satellites::setFlagOrbitLines(bool b) Satellite::orbitLinesFlag = b; } -bool Satellites::getFlagOrbitLines() const +bool Satellites::getFlagOrbitLines() { return Satellite::orbitLinesFlag; } @@ -2093,6 +2176,9 @@ void Satellites::draw(StelCore* core) if (GETSTELMODULE(StelObjectMgr)->getFlagSelectedObjectPointer()) drawPointer(core, painter); + + if (getFlagUmbraVisible()) + drawCircles(core); } void Satellites::drawPointer(StelCore* core, StelPainter& painter) @@ -2125,6 +2211,89 @@ void Satellites::drawPointer(StelCore* core, StelPainter& painter) } } +void Satellites::drawCircles(StelCore* core) +{ + StelPainter sPainter(core->getProjection(StelCore::FrameHeliocentricEclipticJ2000, StelCore::RefractionAuto)); + + sPainter.setBlending(true, GL_ONE, GL_ONE); + sPainter.setLineSmooth(true); + sPainter.setFont(labelFont); + + double lambda, beta, satDistance; + const Vec3d pos = earth->getEclipticPos(); + const Vec3d dir = - sun->getAberrationPush() + pos; + StelUtils::rectToSphe(&lambda, &beta, dir); + const Mat4d rot=Mat4d::zrotation(lambda)*Mat4d::yrotation(-beta); + + SatelliteP sat = Q_NULLPTR; + const QList<StelObjectP> newSelected = GETSTELMODULE(StelObjectMgr)->getSelectedObject("Satellite"); + if (!newSelected.empty()) + sat = getById(newSelected[0].staticCast<Satellite>()->getCatalogNumberString()); + + if (flagUmbraAtFixedDistance) + satDistance = umbraDistance/AU; // Satellite distance [AU] + else if (!sat.isNull()) + satDistance = sat->getInfoMap(core)["height"].toDouble()/AU; + else + return; + + satDistance += earth->getEquatorialRadius(); + texCross->bind(); + const float shift = 8.f; + const double earthDistance=earth->getHeliocentricEclipticPos().length(); // Earth distance [AU] + const double sunHP = asin(earth->getEquatorialRadius()/earthDistance) * M_180_PI*3600.; // arcsec. + const double satHP = asin(earth->getEquatorialRadius()/satDistance) * M_180_PI*3600.; // arcsec. + const double sunSD = atan(sun->getEquatorialRadius()/earthDistance) * M_180_PI*3600.; // arcsec. + + //Classical Bessel elements instead + double f1, f2; + if (earthShadowEnlargementDanjon) + { + static const double danjonScale=1+1./85.-1./594.; // ~1.01, shadow magnification factor (see Espenak 5000 years Canon) + f1=danjonScale*satHP + sunHP + sunSD; // penumbra radius, arcsec + f2=danjonScale*satHP + sunHP - sunSD; // umbra radius, arcsec + } + else + { + const double mHP1=0.998340*satHP; + f1=1.02*(mHP1 + sunHP + sunSD); // penumbra radius, arcsec + f2=1.02*(mHP1 + sunHP - sunSD); // umbra radius, arcsec + } + const double f1_AU=tan(f1/3600.*M_PI_180)*satDistance; + const double f2_AU=tan(f2/3600.*M_PI_180)*satDistance; + + StelVertexArray umbra(StelVertexArray::LineLoop); + for (int i=0; i<360; ++i) + { + Vec3d point(satDistance, cos(i*M_PI_180)*f2_AU, sin(i*M_PI_180)*f2_AU); + rot.transfo(point); + umbra.vertex.append(pos+point); + } + sPainter.setColor(getUmbraColor(), 1.f); + sPainter.drawStelVertexArray(umbra, false); + + Vec3d point(satDistance, 0.0, 0.0); + rot.transfo(point); + Vec3d coord = pos+point; + sPainter.drawSprite2dMode(coord, 5.f); + QString cuLabel = QString("%1 (h=%2 %3)").arg(q_("C.U."), QString::number(AU*(satDistance - earth->getEquatorialRadius()), 'f', 1), qc_("km","distance")); + sPainter.drawText(coord, cuLabel, 0, shift, shift, false); + + if (getFlagPenumbraVisible()) + { + StelVertexArray penumbra(StelVertexArray::LineLoop); + for (int i=0; i<360; ++i) + { + Vec3d point(satDistance, cos(i*M_PI_180)*f1_AU, sin(i*M_PI_180)*f1_AU); + rot.transfo(point); + penumbra.vertex.append(pos+point); + } + + sPainter.setColor(getPenumbraColor(), 1.f); + sPainter.drawStelVertexArray(penumbra, false); + } +} + bool Satellites::checkJsonFileFormat() { QFile jsonFile(catalogPath); diff --git a/plugins/Satellites/src/Satellites.hpp b/plugins/Satellites/src/Satellites.hpp index 90e66c54b5..2fe931e314 100644 --- a/plugins/Satellites/src/Satellites.hpp +++ b/plugins/Satellites/src/Satellites.hpp @@ -161,9 +161,15 @@ class Satellites : public StelObjectModule Q_PROPERTY(int orbitLineSegments READ getOrbitLineSegments WRITE setOrbitLineSegments NOTIFY orbitLineSegmentsChanged) Q_PROPERTY(int orbitLineFadeSegments READ getOrbitLineFadeSegments WRITE setOrbitLineFadeSegments NOTIFY orbitLineFadeSegmentsChanged) Q_PROPERTY(int orbitLineSegmentDuration READ getOrbitLineSegmentDuration WRITE setOrbitLineSegmentDuration NOTIFY orbitLineSegmentDurationChanged) - Q_PROPERTY(int tleEpochAgeDays READ getTleEpochAgeDays WRITE setTleEpochAgeDays NOTIFY tleEpochAgeDaysChanged) + Q_PROPERTY(int tleEpochAgeDays READ getTleEpochAgeDays WRITE setTleEpochAgeDays NOTIFY tleEpochAgeDaysChanged) Q_PROPERTY(Vec3f invisibleSatelliteColor READ getInvisibleSatelliteColor WRITE setInvisibleSatelliteColor NOTIFY invisibleSatelliteColorChanged) Q_PROPERTY(Vec3f transitSatelliteColor READ getTransitSatelliteColor WRITE setTransitSatelliteColor NOTIFY transitSatelliteColorChanged) + Q_PROPERTY(bool flagUmbraVisible READ getFlagUmbraVisible WRITE setFlagUmbraVisible NOTIFY flagUmbraVisibleChanged) + Q_PROPERTY(bool flagUmbraAtFixedDistance READ getFlagUmbraAtFixedDistance WRITE setFlagUmbraAtFixedDistance NOTIFY flagUmbraAtFixedDistanceChanged) + Q_PROPERTY(double umbraDistance READ getUmbraDistance WRITE setUmbraDistance NOTIFY umbraDistanceChanged) + Q_PROPERTY(Vec3f umbraColor READ getUmbraColor WRITE setUmbraColor NOTIFY umbraColorChanged) + Q_PROPERTY(bool flagPenumbraVisible READ getFlagPenumbraVisible WRITE setFlagPenumbraVisible NOTIFY flagPenumbraVisibleChanged) + Q_PROPERTY(Vec3f penumbraColor READ getPenumbraColor WRITE setPenumbraColor NOTIFY penumbraColorChanged) public: //! @enum UpdateState @@ -393,6 +399,12 @@ signals: void tleEpochAgeDaysChanged(int i); void invisibleSatelliteColorChanged(Vec3f); void transitSatelliteColorChanged(Vec3f); + void flagUmbraVisibleChanged(bool b); + void flagUmbraAtFixedDistanceChanged(bool b); + void umbraColorChanged(Vec3f); + void umbraDistanceChanged(double d); + void flagPenumbraVisibleChanged(bool b); + void penumbraColorChanged(Vec3f); //! Emitted when some of the plugin settings have been changed. //! Used to communicate with the configuration window. @@ -418,17 +430,17 @@ signals: public slots: //! get whether or not the plugin will try to update TLE data from the internet //! @return true if updates are set to be done, false otherwise - bool getUpdatesEnabled(void) const {return updatesEnabled;} + bool getUpdatesEnabled(void) {return updatesEnabled;} //! Set whether the plugin will try to download updates from the Internet. //! Emits settingsChanged() if the value changes. //! @param b if true, updates will be enabled, else they will be disabled. void setUpdatesEnabled(bool enabled); - bool isAutoAddEnabled() const { return autoAddEnabled; } + bool isAutoAddEnabled() { return autoAddEnabled; } //! Emits settingsChanged() if the value changes. void setAutoAddEnabled(bool enabled); - bool isAutoRemoveEnabled() const { return autoRemoveEnabled; } + bool isAutoRemoveEnabled() { return autoRemoveEnabled; } //! Emits settingsChanged() if the value changes. void setAutoRemoveEnabled(bool enabled); @@ -436,36 +448,36 @@ public slots: //! Note that hint visibility also applies to satellite labels. //! Emits settingsChanged() if the value changes. void setFlagHintsVisible(bool b); - bool getFlagHintsVisible() const {return hintFader;} + bool getFlagHintsVisible() {return hintFader;} //! Set whether text labels should be displayed next to satellite hints. //! Emits settingsChanged() if the value changes. //! @todo Decide how to sync with "actionShow_Satellite_Labels". void setFlagLabelsVisible(bool b); - bool getFlagLabelsVisible() const; + bool getFlagLabelsVisible(); //! Emits settingsChanged() if the value changes. void setFlagIconicMode(bool b); - bool getFlagIconicMode() const; + bool getFlagIconicMode(); - bool getFlagHideInvisible() const; + bool getFlagHideInvisible(); void setFlagHideInvisible(bool b); //! Get color for invisible satellites //! @return color - Vec3f getInvisibleSatelliteColor() const; + Vec3f getInvisibleSatelliteColor(); //! Set color for invisible satellites void setInvisibleSatelliteColor(const Vec3f& c); //! Get color for satellites in transit through the Sun or the Moon (color of markers) //! @return color - Vec3f getTransitSatelliteColor() const; + Vec3f getTransitSatelliteColor(); //! Set color for satellites in transit through the Sun or the Moon (color of markers) void setTransitSatelliteColor(const Vec3f& c); //! get the label font size. //! @return the pixel size of the font - int getLabelFontSize() const {return labelFont.pixelSize();} + int getLabelFontSize() {return labelFont.pixelSize();} //! set the label font size. //! @param size the pixel size of the font //! Emits settingsChanged() if the value changes. @@ -496,30 +508,63 @@ public slots: //! @param b - true to turn on orbit lines, false to turn off void setFlagOrbitLines(bool b); //! Get the current status of the orbit line rendering flag. - bool getFlagOrbitLines() const; + bool getFlagOrbitLines(); //! return number of segments for orbit lines - int getOrbitLineSegments() const {return Satellite::orbitLineSegments;} + int getOrbitLineSegments() {return Satellite::orbitLineSegments;} //! set number of segments for orbit lines void setOrbitLineSegments(int s); //! return number of fading segments at end of orbit - int getOrbitLineFadeSegments() const {return Satellite::orbitLineFadeSegments;} + int getOrbitLineFadeSegments() {return Satellite::orbitLineFadeSegments;} //! set number of fading segments at end of orbit void setOrbitLineFadeSegments(int s); //! return duration of a single segments - int getOrbitLineSegmentDuration() const {return Satellite::orbitLineSegmentDuration;} + int getOrbitLineSegmentDuration() {return Satellite::orbitLineSegmentDuration;} //! set duration of a single segments void setOrbitLineSegmentDuration(int s); //! return the valid age of TLE's epoch - int getTleEpochAgeDays() const { return Satellite::tleEpochAge; } + int getTleEpochAgeDays() { return Satellite::tleEpochAge; } //! set the valid age of TLE's epoch void setTleEpochAgeDays(int age); void recalculateOrbitLines(void); + //! Set whether ring of Earth's umbra should be displayed. + //! Emits settingsChanged() if the value changes. + void setFlagUmbraVisible(bool b); + bool getFlagUmbraVisible() { return flagUmbraVisible; } + + //! Set whether ring of Earth's umbra should be displayed at fixed distance. + //! Emits settingsChanged() if the value changes. + void setFlagUmbraAtFixedDistance(bool b); + bool getFlagUmbraAtFixedDistance() { return flagUmbraAtFixedDistance; } + + //! Get color for ring of Earth's umbra + //! @return color + Vec3f getUmbraColor() { return umbraColor; } + //! Set color for ring of Earth's umbra + void setUmbraColor(const Vec3f& c); + + //! Get the fixed distance for center of visualized Earth's umbra + //! @return distance, km + double getUmbraDistance() { return umbraDistance; } + //! Set the fixed distance for center of visualized Earth's umbra + void setUmbraDistance(double d); + + //! Set whether ring of Earth's penumbra should be displayed. + //! Emits settingsChanged() if the value changes. + void setFlagPenumbraVisible(bool b); + bool getFlagPenumbraVisible() { return flagPenumbraVisible; } + + //! Get color for ring of Earth's penumbra + //! @return color + Vec3f getPenumbraColor() { return penumbraColor; } + //! Set color for ring of Earth's penumbra + void setPenumbraColor(const Vec3f& c); + //! Display a message on the screen for a few seconds. //! This is used for plugin-specific warnings and such. void displayMessage(const QString& message, const QString hexColor="#999999"); @@ -539,8 +584,11 @@ private slots: //! Call when button "Save settings" in main GUI are pressed void saveSettings() { saveSettingsToConfig(); } void translateData(); + void updateEarthShadowEnlargementFlag(bool state) { earthShadowEnlargementDanjon=state; } private: + //! Drawing the circles of Earth's umbra and penumbra + void drawCircles(StelCore* core); //! Add to the current collection the satellite described by the data. //! @warning Use only in other methods! Does not update satelliteListModel! //! @todo This probably could be done easier if Satellite had a constructor @@ -618,13 +666,13 @@ private: QSet<QString> groups; LinearFader hintFader; - StelTextureSP texPointer; + StelTextureSP texPointer, texCross; //! @name Bottom toolbar button //@{ StelButton* toolbarButton; //@} - QSharedPointer<Planet> earth; + QSharedPointer<Planet> earth, sun; Vec3f defaultHintColor; QFont labelFont; @@ -660,6 +708,22 @@ private: QDateTime lastUpdate; int updateFrequencyHours; //@} + + //! @name Umbra/penumbra module + //@{ + //! Flag enabling visualization the Earth's umbra. + bool flagUmbraVisible; + //! Flag enabling visualization the Earth's umbra at fixed distance + bool flagUmbraAtFixedDistance; + Vec3f umbraColor; + //! The distance for center of visualized Earth's umbra in kilometers + double umbraDistance; + //! Flag enabling visualization the Earth's penumbra. + bool flagPenumbraVisible; + Vec3f penumbraColor; + //! Used to track whether earth shadow enlargement shall be computed after Danjon (1951) + bool earthShadowEnlargementDanjon; + //@} //! @name Screen message infrastructure //@{ diff --git a/plugins/Satellites/src/gui/SatellitesDialog.cpp b/plugins/Satellites/src/gui/SatellitesDialog.cpp index d346738b57..86d3121626 100644 --- a/plugins/Satellites/src/gui/SatellitesDialog.cpp +++ b/plugins/Satellites/src/gui/SatellitesDialog.cpp @@ -167,29 +167,42 @@ void SatellitesDialog::createDialogContent() connect(updateTimer, SIGNAL(timeout()), this, SLOT(updateCountdown())); updateTimer->start(7000); - // Settings tab / General settings group - connectBoolProperty(ui->labelsGroup, "Satellites.flagLabelsVisible"); - connectIntProperty(ui->fontSizeSpinBox, "Satellites.labelFontSize"); - connect(ui->restoreDefaultsButton, SIGNAL(clicked()), this, SLOT(restoreDefaults())); - connect(ui->saveSettingsButton, SIGNAL(clicked()), this, SLOT(saveSettings())); - - // Settings tab / realistic mode group - connectBoolProperty(ui->iconicGroup, "Satellites.flagIconicMode"); + // Settings tab / Visualisation settings group + // Logic sub-group: Labels + connectBoolProperty(ui->labelsCheckBox, "Satellites.flagLabelsVisible"); + connectIntProperty(ui->fontSizeSpinBox, "Satellites.labelFontSize"); + connect(ui->labelsCheckBox, SIGNAL(clicked(bool)), ui->fontSizeSpinBox, SLOT(setEnabled(bool))); + ui->fontSizeSpinBox->setEnabled(ui->labelsCheckBox->isChecked()); + // Logic sub-group: Orbit lines + connectBoolProperty(ui->orbitLinesCheckBox, "Satellites.flagOrbitLines"); + connectIntProperty(ui->orbitSegmentsSpin, "Satellites.orbitLineSegments"); + connectIntProperty(ui->orbitFadeSpin, "Satellites.orbitLineFadeSegments"); + connectIntProperty(ui->orbitDurationSpin, "Satellites.orbitLineSegmentDuration"); + connect(ui->orbitLinesCheckBox, SIGNAL(clicked(bool)), this, SLOT(handleOrbitLinesGroup(bool))); + handleOrbitLinesGroup(ui->orbitLinesCheckBox->isChecked()); + // Logic sub-group: Umbra + connectBoolProperty(ui->umbraCheckBox, "Satellites.flagUmbraVisible"); + connectBoolProperty(ui->umbraAtDistance, "Satellites.flagUmbraAtFixedDistance"); + connectDoubleProperty(ui->umbraDistance, "Satellites.umbraDistance"); + connect(ui->umbraCheckBox, SIGNAL(clicked(bool)), this, SLOT(handleUmbraGroup(bool))); + handleUmbraGroup(ui->umbraCheckBox->isChecked()); + // Logic sub-group: Markers + connectBoolProperty(ui->iconicCheckBox, "Satellites.flagIconicMode"); connectBoolProperty(ui->hideInvisibleSatellites, "Satellites.flagHideInvisible"); - - // Settings tab / colors group + connect(ui->iconicCheckBox, SIGNAL(clicked(bool)), ui->hideInvisibleSatellites, SLOT(setEnabled(bool))); + ui->hideInvisibleSatellites->setEnabled(ui->iconicCheckBox->isChecked()); + // Logic sub-group: Colors connectColorButton(ui->invisibleColorButton, "Satellites.invisibleSatelliteColor", "Satellites/invisible_satellite_color"); connectColorButton(ui->transitColorButton, "Satellites.transitSatelliteColor", "Satellites/transit_satellite_color"); + connectColorButton(ui->umbraColor, "Satellites.umbraColor", "Satellites/umbra_color"); + connectColorButton(ui->penumbraColor, "Satellites.penumbraColor", "Satellites/penumbra_color"); + // Logic sub-group: Penumbra + connectBoolProperty(ui->penumbraCheckBox, "Satellites.flagPenumbraVisible"); - // Settings tab - populate all values + connect(ui->restoreDefaultsButton, SIGNAL(clicked()), this, SLOT(restoreDefaults())); + connect(ui->saveSettingsButton, SIGNAL(clicked()), this, SLOT(saveSettings())); updateSettingsPage(); - // Settings tab / orbit lines group - connectBoolProperty(ui->orbitLinesGroup, "Satellites.flagOrbitLines"); - connectIntProperty(ui->orbitSegmentsSpin, "Satellites.orbitLineSegments"); - connectIntProperty(ui->orbitFadeSpin, "Satellites.orbitLineFadeSegments"); - connectIntProperty(ui->orbitDurationSpin, "Satellites.orbitLineSegmentDuration"); - // Satellites tab filterModel = new SatellitesListFilterModel(this); filterModel->setSourceModel(plugin->getSatellitesListModel()); @@ -274,6 +287,24 @@ void SatellitesDialog::createDialogContent() QString style = "QLabel { color: rgb(238, 238, 238); }"; ui->labelAutoAdd->setStyleSheet(style); + ui->labelTle->setStyleSheet(style); + ui->labelTleEpoch->setStyleSheet(style); + ui->labelTleEpochData->setStyleSheet(style); + ui->validAgeLabel->setStyleSheet(style); +} + +void SatellitesDialog::handleOrbitLinesGroup(bool state) +{ + ui->orbitSegmentsSpin->setEnabled(state); + ui->orbitFadeSpin->setEnabled(state); + ui->orbitDurationSpin->setEnabled(state); +} + +void SatellitesDialog::handleUmbraGroup(bool state) +{ + ui->umbraAtDistance->setEnabled(state); + ui->umbraDistance->setEnabled(state); + ui->penumbraCheckBox->setEnabled(state); } void SatellitesDialog::askSatMarkerColor() @@ -967,6 +998,11 @@ void SatellitesDialog::restoreDefaults(void) updateSettingsPage(); populateFilterMenu(); populateSourcesList(); + // handle GUI elements + ui->fontSizeSpinBox->setEnabled(ui->labelsCheckBox->isChecked()); + handleOrbitLinesGroup(ui->orbitLinesCheckBox->isChecked()); + handleUmbraGroup(ui->umbraCheckBox->isChecked()); + ui->hideInvisibleSatellites->setEnabled(ui->iconicCheckBox->isChecked()); } else qDebug() << "[Satellites] restore defaults is canceled..."; @@ -1048,11 +1084,17 @@ void SatellitesDialog::populateInfo() ui->labelRCS->setToolTip(QString("<p>%1</p>").arg(q_("Radar cross-section (RCS) is a measure of how detectable an object is with a radar. A larger RCS indicates that an object is more easily detected."))); ui->labelStdMagnitude->setToolTip(QString("<p>%1</p>").arg(q_("The standard magnitude of a satellite is defined as its apparent magnitude when at half-phase and at a distance 1000 km from the observer."))); // TRANSLATORS: duration - ui->orbitDurationSpin->setSuffix(qc_(" s","time unit")); - // TRANSLATORS: duration - ui->labelSegmentLength->setText(q_("Segment length:")); + QString s = qc_("s","time"); + ui->orbitDurationSpin->setSuffix(QString(" %1").arg(s)); // TRANSLATORS: duration - ui->updateFrequencySpinBox->setSuffix(qc_(" h","time unit")); + ui->updateFrequencySpinBox->setSuffix(QString(" %1").arg(qc_("h","time"))); + // TRANSLATORS: Unit of measure for distance - kilometers + QString km = qc_("km", "distance"); + ui->umbraDistance->setSuffix(QString(" %1").arg(km)); + ui->umbraDistance->setToolTip(QString("<p>%1. %2: %3-%4 %5</p>").arg(q_("Distance to the center of umbra from Earth's surface (height of imagined satellite)"), q_("Valid range"), QString::number(ui->umbraDistance->minimum(), 'f', 1), QString::number(ui->umbraDistance->maximum(), 'f', 1), km)); + ui->orbitSegmentsSpin->setToolTip(QString("<p>%1. %2: %3-%4</p>").arg(q_("Number of segments: number of segments used to draw the line"), q_("Valid range"), QString::number(ui->orbitSegmentsSpin->minimum()), QString::number(ui->orbitSegmentsSpin->maximum()))); + ui->orbitDurationSpin->setToolTip(QString("<p>%1. %2: %3-%4%5</p>").arg(q_("Segment length: duration of a single segment in seconds"), q_("Valid range"), QString::number(ui->orbitDurationSpin->minimum()), QString::number(ui->orbitDurationSpin->maximum()), s)); + ui->orbitFadeSpin->setToolTip(QString("<p>%1. %2: %3-%4</p>").arg(q_("Fade length: number of segments used to draw each end of the line"), q_("Valid range"), QString::number(ui->orbitFadeSpin->minimum()), QString::number(ui->orbitFadeSpin->maximum()))); } void SatellitesDialog::populateSourcesList() diff --git a/plugins/Satellites/src/gui/SatellitesDialog.hpp b/plugins/Satellites/src/gui/SatellitesDialog.hpp index e890300bd3..51095312a8 100644 --- a/plugins/Satellites/src/gui/SatellitesDialog.hpp +++ b/plugins/Satellites/src/gui/SatellitesDialog.hpp @@ -88,6 +88,8 @@ private slots: void saveSatellites(void); void showUpdateState(Satellites::UpdateState state); void showUpdateCompleted(int updated, int total, int added, int missing); + void handleOrbitLinesGroup(bool state); + void handleUmbraGroup(bool state); //! @name Sources Tab //@{ diff --git a/plugins/Satellites/src/gui/satellitesDialog.ui b/plugins/Satellites/src/gui/satellitesDialog.ui index 69f0ca0fe0..93d8b4a4a3 100644 --- a/plugins/Satellites/src/gui/satellitesDialog.ui +++ b/plugins/Satellites/src/gui/satellitesDialog.ui @@ -339,71 +339,34 @@ </widget> </item> <item> - <layout class="QHBoxLayout" name="horizontalLayout_9"> - <property name="spacing"> - <number>0</number> + <widget class="QGroupBox" name="visualisationBox"> + <property name="title"> + <string>Visualisation settings</string> </property> - <item> - <widget class="QGroupBox" name="labelsGroup"> - <property name="title"> - <string>Labels</string> - </property> - <property name="flat"> - <bool>true</bool> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - <layout class="QGridLayout" name="gridLayout_2"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item row="1" column="2"> - <widget class="QSpinBox" name="fontSizeSpinBox"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - <property name="suffix"> - <string comment="pixels">px</string> - </property> - <property name="minimum"> - <number>-100</number> - </property> - <property name="maximum"> - <number>200</number> - </property> - <property name="value"> - <number>10</number> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_10"> + <layout class="QGridLayout" name="gridLayout_9"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item row="1" column="0"> + <layout class="QHBoxLayout" name="horizontalLayout_16"> + <item> + <widget class="QCheckBox" name="orbitLinesCheckBox"> <property name="text"> - <string>Font size:</string> - </property> - <property name="buddy"> - <cstring>fontSizeSpinBox</cstring> + <string>Orbit lines</string> </property> </widget> </item> - <item row="1" column="1"> - <spacer name="horizontalSpacer_3"> + <item> + <spacer name="horizontalSpacer_13"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> @@ -415,132 +378,29 @@ </property> </spacer> </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="colorsGroup"> - <property name="title"> - <string>Colors</string> - </property> - <layout class="QGridLayout" name="gridLayout_6"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item row="0" column="0"> - <widget class="QToolButton" name="invisibleColorButton"> + <item> + <widget class="QSpinBox" name="orbitSegmentsSpin"> <property name="toolTip"> - <string>Color of markers, labels and orbits for invisible satellites</string> - </property> - <property name="text"> <string/> </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QToolButton" name="transitColorButton"> - <property name="toolTip"> - <string>Color of markers for satellites in transit through the Sun or the Moon</string> - </property> - <property name="text"> - <string notr="true"/> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="iconicGroup"> - <property name="title"> - <string>Show satellites as markers</string> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - <property name="checked"> - <bool>false</bool> - </property> - <layout class="QGridLayout" name="gridLayout_4"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item row="0" column="0"> - <widget class="QCheckBox" name="hideInvisibleSatellites"> - <property name="text"> - <string>Hide invisible artificial satellites</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_14"> - <item> - <widget class="QGroupBox" name="orbitLinesGroup"> - <property name="title"> - <string>Orbit lines</string> - </property> - <property name="flat"> - <bool>true</bool> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - <layout class="QGridLayout" name="gridLayout_3"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item row="0" column="7"> - <widget class="QSpinBox" name="orbitFadeSpin"> - <property name="toolTip"> - <string>Number of segments used to draw each end of the line</string> - </property> <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> + <property name="minimum"> + <number>3</number> + </property> <property name="maximum"> - <number>50</number> + <number>9000</number> </property> <property name="value"> - <number>5</number> + <number>180</number> </property> </widget> </item> - <item row="0" column="4"> + <item> <widget class="QSpinBox" name="orbitDurationSpin"> <property name="toolTip"> - <string>Duration of a single segment in seconds</string> + <string/> </property> <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> @@ -556,27 +416,35 @@ </property> </widget> </item> - <item row="0" column="1"> - <widget class="QSpinBox" name="orbitSegmentsSpin"> + <item> + <widget class="QSpinBox" name="orbitFadeSpin"> <property name="toolTip"> - <string>Number of segments used to draw the line</string> + <string/> </property> <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> - <property name="minimum"> - <number>3</number> - </property> <property name="maximum"> - <number>9000</number> + <number>50</number> </property> <property name="value"> - <number>180</number> + <number>5</number> </property> </widget> </item> - <item row="0" column="5"> - <spacer name="horizontalSpacer_5"> + </layout> + </item> + <item row="0" column="2"> + <layout class="QHBoxLayout" name="horizontalLayout_15"> + <item> + <widget class="QCheckBox" name="iconicCheckBox"> + <property name="text"> + <string>Show satellites as markers</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_4"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> @@ -588,47 +456,180 @@ </property> </spacer> </item> - <item row="0" column="3"> - <widget class="QLabel" name="labelSegmentLength"> + <item> + <widget class="QToolButton" name="transitColorButton"> <property name="toolTip"> - <string>Duration of a single segment</string> + <string>Color of markers for satellites in transit through the Sun or the Moon</string> </property> <property name="text"> - <string>Segment length:</string> + <string notr="true"/> </property> - <property name="buddy"> - <cstring>orbitDurationSpin</cstring> + </widget> + </item> + </layout> + </item> + <item row="2" column="0"> + <layout class="QHBoxLayout" name="horizontalLayout_9"> + <item> + <widget class="QCheckBox" name="umbraCheckBox"> + <property name="text"> + <string>Show Earth's umbra</string> </property> </widget> </item> - <item row="0" column="0"> - <widget class="QLabel" name="label_5"> + <item> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QToolButton" name="umbraColor"> <property name="toolTip"> - <string>Number of segments used to draw the line</string> + <string>The color of Earth's umbra circle</string> </property> + </widget> + </item> + </layout> + </item> + <item row="2" column="2"> + <layout class="QHBoxLayout" name="horizontalLayout_14"> + <item> + <widget class="QCheckBox" name="penumbraCheckBox"> <property name="text"> - <string>Number of segments:</string> + <string>Show Earth's penumbra</string> </property> - <property name="buddy"> - <cstring>orbitSegmentsSpin</cstring> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_9"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QToolButton" name="penumbraColor"> + <property name="toolTip"> + <string>The color of Earth's penumbra circle</string> </property> </widget> </item> - <item row="0" column="6"> - <widget class="QLabel" name="label_6"> + </layout> + </item> + <item row="1" column="2"> + <layout class="QHBoxLayout" name="horizontalLayout_18"> + <item> + <widget class="QCheckBox" name="hideInvisibleSatellites"> + <property name="text"> + <string>Hide invisible artificial satellites</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_5"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QToolButton" name="invisibleColorButton"> <property name="toolTip"> - <string>Number of segments used to draw each end of the line</string> + <string>Color of markers, labels and orbits for invisible satellites</string> </property> <property name="text"> - <string>Fade length:</string> + <string/> </property> - <property name="buddy"> - <cstring>orbitFadeSpin</cstring> + </widget> + </item> + </layout> + </item> + <item row="0" column="0"> + <layout class="QHBoxLayout" name="horizontalLayout_13"> + <item> + <widget class="QCheckBox" name="labelsCheckBox"> + <property name="text"> + <string>Labels</string> </property> </widget> </item> - <item row="0" column="2"> - <spacer name="horizontalSpacer_4"> + <item> + <spacer name="horizontalSpacer_11"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QSpinBox" name="fontSizeSpinBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Font size for labels</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="suffix"> + <string comment="pixels">px</string> + </property> + <property name="minimum"> + <number>-100</number> + </property> + <property name="maximum"> + <number>200</number> + </property> + <property name="value"> + <number>10</number> + </property> + </widget> + </item> + </layout> + </item> + <item row="3" column="0"> + <layout class="QHBoxLayout" name="horizontalLayout_17"> + <item> + <widget class="QCheckBox" name="umbraAtDistance"> + <property name="toolTip"> + <string>Distance to the center of umbra from Earth's surface (height of imagined satellite)</string> + </property> + <property name="text"> + <string>Show umbra at distance:</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_14"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> @@ -640,10 +641,48 @@ </property> </spacer> </item> + <item> + <widget class="QDoubleSpinBox" name="umbraDistance"> + <property name="minimumSize"> + <size> + <width>120</width> + <height>0</height> + </size> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="decimals"> + <number>1</number> + </property> + <property name="minimum"> + <double>75.000000000000000</double> + </property> + <property name="maximum"> + <double>400000.000000000000000</double> + </property> + </widget> + </item> </layout> - </widget> - </item> - </layout> + </item> + <item row="0" column="1"> + <spacer name="horizontalSpacer_12"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> </item> <item> <spacer name="verticalSpacer_3"> @@ -1515,15 +1554,6 @@ <tabstop>checkBoxAutoRemove</tabstop> <tabstop>updateFrequencySpinBox</tabstop> <tabstop>updateButton</tabstop> - <tabstop>labelsGroup</tabstop> - <tabstop>fontSizeSpinBox</tabstop> - <tabstop>invisibleColorButton</tabstop> - <tabstop>transitColorButton</tabstop> - <tabstop>iconicGroup</tabstop> - <tabstop>hideInvisibleSatellites</tabstop> - <tabstop>orbitSegmentsSpin</tabstop> - <tabstop>orbitDurationSpin</tabstop> - <tabstop>orbitFadeSpin</tabstop> <tabstop>restoreDefaultsButton</tabstop> <tabstop>saveSettingsButton</tabstop> <tabstop>tabs</tabstop> |