File indexing completed on 2024-05-05 03:50:42
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // SPDX-FileCopyrightText: 2012 Rene Kuettner <rene@bitkanal.net> 0004 // 0005 0006 #include "EclipsesPlugin.h" 0007 0008 #include "MarbleWidget.h" 0009 #include "MarbleColors.h" 0010 #include "MarbleDebug.h" 0011 #include "MarbleModel.h" 0012 #include "MarbleClock.h" 0013 #include "ViewportParams.h" 0014 #include "GeoPainter.h" 0015 0016 #include "EclipsesModel.h" 0017 #include "EclipsesItem.h" 0018 #include "EclipsesBrowserDialog.h" 0019 0020 #include "ui_EclipsesConfigDialog.h" 0021 #include "ui_EclipsesReminderDialog.h" 0022 0023 #include <QMenu> 0024 #include <QPushButton> 0025 0026 namespace Marble 0027 { 0028 0029 EclipsesPlugin::EclipsesPlugin() 0030 : RenderPlugin( nullptr ), 0031 m_isInitialized( false ), 0032 m_marbleWidget( nullptr ), 0033 m_model( nullptr ), 0034 m_eclipsesActionGroup( nullptr ), 0035 m_eclipsesMenuAction( nullptr ), 0036 m_eclipsesListMenu( nullptr ), 0037 m_menuYear( 0 ), 0038 m_configDialog( nullptr ), 0039 m_configWidget( nullptr ), 0040 m_browserDialog( nullptr ), 0041 m_reminderDialog( nullptr ), 0042 m_reminderWidget( nullptr ) 0043 { 0044 } 0045 0046 EclipsesPlugin::EclipsesPlugin( const MarbleModel *marbleModel ) 0047 : RenderPlugin( marbleModel ), 0048 m_isInitialized( false ), 0049 m_marbleWidget( nullptr ), 0050 m_model( nullptr ), 0051 m_eclipsesActionGroup( nullptr ), 0052 m_eclipsesMenuAction( nullptr ), 0053 m_eclipsesListMenu( nullptr ), 0054 m_menuYear( 0 ), 0055 m_configDialog( nullptr ), 0056 m_configWidget( nullptr ), 0057 m_browserDialog( nullptr ), 0058 m_reminderDialog( nullptr ), 0059 m_reminderWidget( nullptr ) 0060 { 0061 connect( this, SIGNAL(settingsChanged(QString)), 0062 SLOT(updateSettings()) ); 0063 } 0064 0065 EclipsesPlugin::~EclipsesPlugin() 0066 { 0067 if( m_isInitialized ) { 0068 delete m_model; 0069 delete m_eclipsesActionGroup; 0070 delete m_eclipsesListMenu; 0071 delete m_configDialog; 0072 delete m_configWidget; 0073 delete m_browserDialog; 0074 delete m_reminderDialog; 0075 delete m_reminderWidget; 0076 } 0077 } 0078 0079 QStringList EclipsesPlugin::backendTypes() const 0080 { 0081 return QStringList(QStringLiteral("eclipses")); 0082 } 0083 0084 QString EclipsesPlugin::renderPolicy() const 0085 { 0086 return QStringLiteral("ALWAYS"); 0087 } 0088 0089 QStringList EclipsesPlugin::renderPosition() const 0090 { 0091 return QStringList(QStringLiteral("ORBIT")); 0092 } 0093 0094 QString EclipsesPlugin::name() const 0095 { 0096 return tr( "Eclipses" ); 0097 } 0098 0099 QString EclipsesPlugin::nameId() const 0100 { 0101 return QStringLiteral("eclipses"); 0102 } 0103 0104 QString EclipsesPlugin::guiString() const 0105 { 0106 return tr( "E&clipses" ); 0107 } 0108 0109 QString EclipsesPlugin::version() const 0110 { 0111 return QStringLiteral("1.0"); 0112 } 0113 0114 QString EclipsesPlugin::description() const 0115 { 0116 return tr( "This plugin visualizes solar eclipses." ); 0117 } 0118 0119 QString EclipsesPlugin::copyrightYears() const 0120 { 0121 return QStringLiteral("2013"); 0122 } 0123 0124 QVector<PluginAuthor> EclipsesPlugin::pluginAuthors() const 0125 { 0126 return QVector<PluginAuthor>() 0127 << PluginAuthor(QStringLiteral("Rene Kuettner"), QStringLiteral("rene@bitkanal.net")) 0128 << PluginAuthor(QStringLiteral("Gerhard Holtkamp"), QString()); 0129 } 0130 0131 QIcon EclipsesPlugin::icon() const 0132 { 0133 return QIcon(QStringLiteral(":res/eclipses.png")); 0134 } 0135 0136 RenderPlugin::RenderType EclipsesPlugin::renderType() const 0137 { 0138 return RenderPlugin::ThemeRenderType; 0139 //return UnknownRenderType; 0140 } 0141 0142 QList<QActionGroup*>* EclipsesPlugin::actionGroups() const 0143 { 0144 return const_cast<QList<QActionGroup*>*>( &m_actionGroups ); 0145 } 0146 0147 QDialog* EclipsesPlugin::configDialog() 0148 { 0149 Q_ASSERT( m_isInitialized ); 0150 return m_configDialog; 0151 } 0152 0153 void EclipsesPlugin::initialize() 0154 { 0155 if( isInitialized() ) { 0156 return; 0157 } 0158 0159 // initialize dialogs 0160 delete m_configDialog; 0161 m_configDialog = new QDialog(); 0162 delete m_configWidget; 0163 m_configWidget = new Ui::EclipsesConfigDialog(); 0164 m_configWidget->setupUi( m_configDialog ); 0165 0166 connect( m_configDialog, SIGNAL(accepted()), 0167 this, SLOT(writeSettings()) ); 0168 connect( m_configDialog, SIGNAL(rejected()), 0169 this, SLOT(readSettings()) ); 0170 connect( m_configWidget->buttonBox->button( QDialogButtonBox::Reset ), 0171 SIGNAL(clicked()), this, SLOT(readSettings()) ); 0172 connect( m_configWidget->buttonBox->button( QDialogButtonBox::Apply ), 0173 SIGNAL(clicked()), this, SLOT(writeSettings()) ); 0174 connect( m_configWidget->buttonBox->button( QDialogButtonBox::Apply ), 0175 SIGNAL(clicked()), this, SLOT(updateEclipses()) ); 0176 0177 m_browserDialog = new EclipsesBrowserDialog( marbleModel() ); 0178 connect( m_browserDialog, SIGNAL(buttonShowClicked(int,int)), 0179 this, SLOT(showEclipse(int,int)) ); 0180 connect( m_browserDialog, SIGNAL(buttonSettingsClicked()), 0181 m_configDialog, SLOT(show()) ); 0182 0183 delete m_reminderDialog; 0184 m_reminderDialog = new QDialog(); 0185 delete m_reminderWidget; 0186 m_reminderWidget = new Ui::EclipsesReminderDialog(); 0187 m_reminderWidget->setupUi( m_reminderDialog ); 0188 0189 // initialize menu entries 0190 m_eclipsesActionGroup = new QActionGroup( this ); 0191 m_actionGroups.append( m_eclipsesActionGroup ); 0192 0193 m_eclipsesListMenu = new QMenu(); 0194 m_eclipsesActionGroup->addAction( m_eclipsesListMenu->menuAction() ); 0195 connect( m_eclipsesListMenu, SIGNAL(triggered(QAction*)), 0196 this, SLOT(showEclipseFromMenu(QAction*)) ); 0197 0198 m_eclipsesMenuAction = new QAction( 0199 tr("Browse Ecli&pses..."), m_eclipsesActionGroup ); 0200 m_eclipsesMenuAction->setIcon(QIcon(QStringLiteral(":res/eclipses.png"))); 0201 m_eclipsesActionGroup->addAction( m_eclipsesMenuAction ); 0202 connect( m_eclipsesMenuAction, SIGNAL(triggered()), 0203 m_browserDialog, SLOT(show()) ); 0204 0205 // initialize eclipses model 0206 m_model = new EclipsesModel( marbleModel() ); 0207 0208 connect( marbleModel()->clock(), SIGNAL(timeChanged()), 0209 this, SLOT(updateEclipses()) ); 0210 0211 m_isInitialized = true; 0212 0213 readSettings(); 0214 updateEclipses(); 0215 updateMenuItemState(); 0216 updateSettings(); 0217 } 0218 0219 bool EclipsesPlugin::isInitialized() const 0220 { 0221 return m_isInitialized; 0222 } 0223 0224 bool EclipsesPlugin::eventFilter( QObject *object, QEvent *e ) 0225 { 0226 // delayed initialization of pointer to marble widget 0227 MarbleWidget *widget = dynamic_cast<MarbleWidget*> (object); 0228 if ( widget && m_marbleWidget != widget ) { 0229 connect( widget, SIGNAL(themeChanged(QString)), 0230 this, SLOT(updateMenuItemState()) ); 0231 m_marbleWidget = widget; 0232 } 0233 0234 return RenderPlugin::eventFilter(object, e); 0235 } 0236 0237 bool EclipsesPlugin::render( GeoPainter *painter, 0238 ViewportParams *viewport, 0239 const QString &renderPos, 0240 GeoSceneLayer *layer ) 0241 { 0242 Q_UNUSED( viewport ); 0243 Q_UNUSED( renderPos ); 0244 Q_UNUSED( layer ); 0245 0246 if (marbleModel()->planetId() == QLatin1String("earth")) { 0247 for( EclipsesItem *item: m_model->items() ) { 0248 if( item->takesPlaceAt( marbleModel()->clock()->dateTime() ) ) { 0249 return renderItem( painter, item ); 0250 } 0251 } 0252 } 0253 0254 return true; 0255 } 0256 0257 bool EclipsesPlugin::renderItem( GeoPainter *painter, EclipsesItem *item ) const 0258 { 0259 int phase = item->phase(); 0260 0261 // Draw full penumbra shadow cone 0262 if( m_configWidget->checkBoxShowFullPenumbra->isChecked() ) { 0263 painter->setPen( Oxygen::aluminumGray1 ); 0264 QColor sunBoundingBrush ( Oxygen::aluminumGray6 ); 0265 sunBoundingBrush.setAlpha( 48 ); 0266 painter->setBrush( sunBoundingBrush ); 0267 painter->drawPolygon( item->shadowConePenumbra() ); 0268 } 0269 0270 // Draw 60% penumbra shadow cone 0271 if( m_configWidget->checkBoxShow60MagPenumbra->isChecked() ) { 0272 painter->setPen( Oxygen::aluminumGray2 ); 0273 QColor penumbraBrush ( Oxygen::aluminumGray6 ); 0274 penumbraBrush.setAlpha( 96 ); 0275 painter->setBrush( penumbraBrush ); 0276 painter->drawPolygon( item->shadowCone60MagPenumbra() ); 0277 } 0278 0279 // Draw southern boundary of the penumbra 0280 if( m_configWidget->checkBoxShowSouthernPenumbra->isChecked() ) { 0281 QColor southernBoundaryColor(Oxygen::brickRed1); 0282 southernBoundaryColor.setAlpha(128); 0283 QPen southernBoundary(southernBoundaryColor); 0284 southernBoundary.setWidth(3); 0285 painter->setPen( southernBoundary ); 0286 painter->drawPolyline( item->southernPenumbra() ); 0287 painter->setPen( Oxygen::brickRed5 ); 0288 painter->drawPolyline( item->southernPenumbra() ); 0289 } 0290 0291 // Draw northern boundary of the penumbra 0292 if( m_configWidget->checkBoxShowNorthernPenumbra->isChecked() ) { 0293 QColor northernBoundaryColor(Oxygen::brickRed1); 0294 northernBoundaryColor.setAlpha(128); 0295 QPen northernBoundary(northernBoundaryColor); 0296 northernBoundary.setWidth(3); 0297 painter->setPen( northernBoundary ); 0298 painter->drawPolyline( item->northernPenumbra() ); 0299 painter->setPen( Oxygen::brickRed5 ); 0300 painter->drawPolyline( item->northernPenumbra() ); 0301 } 0302 0303 // Draw Sunrise / Sunset Boundaries 0304 if( m_configWidget->checkBoxShowSunBoundaries->isChecked() ) { 0305 painter->setPen( Oxygen::hotOrange6 ); 0306 const QList<GeoDataLinearRing> boundaries = item->sunBoundaries(); 0307 QList<GeoDataLinearRing>::const_iterator i = boundaries.constBegin(); 0308 QColor sunBoundingBrush ( Oxygen::hotOrange5 ); 0309 sunBoundingBrush.setAlpha( 64 ); 0310 painter->setBrush( sunBoundingBrush ); 0311 for( ; i != boundaries.constEnd(); ++i ) { 0312 painter->drawPolygon( *i ); 0313 } 0314 } 0315 0316 // total or annular eclipse 0317 if( m_configWidget->checkBoxShowUmbra->isChecked() && phase > 3 ) 0318 { 0319 painter->setPen( Oxygen::aluminumGray4 ); 0320 QColor sunBoundingBrush ( Oxygen::aluminumGray6 ); 0321 sunBoundingBrush.setAlpha( 128 ); 0322 painter->setBrush( sunBoundingBrush ); 0323 painter->drawPolygon( item->umbra() ); 0324 0325 // draw shadow cone 0326 painter->setPen( Qt::black ); 0327 QColor shadowConeBrush ( Oxygen::aluminumGray6 ); 0328 shadowConeBrush.setAlpha( 128 ); 0329 painter->setBrush( shadowConeBrush ); 0330 painter->drawPolygon( item->shadowConeUmbra() ); 0331 } 0332 0333 // plot central line 0334 if( m_configWidget->checkBoxShowCentralLine->isChecked() && phase > 3 ) { 0335 painter->setPen( Qt::black ); 0336 painter->drawPolyline( item->centralLine() ); 0337 } 0338 0339 // mark point of maximum eclipse 0340 if( m_configWidget->checkBoxShowMaximum->isChecked() ) { 0341 painter->setPen( Qt::white ); 0342 QColor sunBoundingBrush ( Qt::white ); 0343 sunBoundingBrush.setAlpha( 128 ); 0344 painter->setBrush( sunBoundingBrush ); 0345 0346 painter->drawEllipse( item->maxLocation(), 15, 15 ); 0347 painter->setPen( Oxygen::brickRed4 ); 0348 painter->drawText( item->maxLocation(), tr( "Maximum of Eclipse" ) ); 0349 } 0350 0351 return true; 0352 } 0353 0354 QHash<QString, QVariant> EclipsesPlugin::settings() const 0355 { 0356 return RenderPlugin::settings(); 0357 } 0358 0359 void EclipsesPlugin::setSettings( const QHash<QString, QVariant> &settings ) 0360 { 0361 RenderPlugin::setSettings( settings ); 0362 m_settings = settings; 0363 emit settingsChanged( nameId() ); 0364 } 0365 0366 void EclipsesPlugin::readSettings() 0367 { 0368 m_configWidget->checkBoxEnableLunarEclipses->setChecked( 0369 m_settings.value(QStringLiteral("enableLunarEclipses"), false).toBool()); 0370 m_configWidget->checkBoxShowMaximum->setChecked( 0371 m_settings.value(QStringLiteral("showMaximum"), true).toBool()); 0372 m_configWidget->checkBoxShowUmbra->setChecked( 0373 m_settings.value(QStringLiteral("showUmbra"), true).toBool()); 0374 m_configWidget->checkBoxShowSouthernPenumbra->setChecked( 0375 m_settings.value(QStringLiteral("showSouthernPenumbra"), true).toBool()); 0376 m_configWidget->checkBoxShowNorthernPenumbra->setChecked( 0377 m_settings.value(QStringLiteral("showNorthernPenumbra"), true).toBool()); 0378 m_configWidget->checkBoxShowCentralLine->setChecked( 0379 m_settings.value(QStringLiteral("showCentralLine"), true).toBool()); 0380 m_configWidget->checkBoxShowFullPenumbra->setChecked( 0381 m_settings.value(QStringLiteral("showFullPenumbra"), true).toBool()); 0382 m_configWidget->checkBoxShow60MagPenumbra->setChecked( 0383 m_settings.value(QStringLiteral("show60MagPenumbra"), false).toBool()); 0384 m_configWidget->checkBoxShowSunBoundaries->setChecked( 0385 m_settings.value(QStringLiteral("showSunBoundaries"), true).toBool()); 0386 } 0387 0388 void EclipsesPlugin::writeSettings() 0389 { 0390 m_settings.insert(QStringLiteral("enableLunarEclipses"), 0391 m_configWidget->checkBoxEnableLunarEclipses->isChecked() ); 0392 m_settings.insert(QStringLiteral("showMaximum"), 0393 m_configWidget->checkBoxShowMaximum->isChecked() ); 0394 m_settings.insert(QStringLiteral("showUmbra"), 0395 m_configWidget->checkBoxShowUmbra->isChecked() ); 0396 m_settings.insert(QStringLiteral("showSouthernPenumbra"), 0397 m_configWidget->checkBoxShowSouthernPenumbra->isChecked() ); 0398 m_settings.insert(QStringLiteral("showNorthernPenumbra"), 0399 m_configWidget->checkBoxShowNorthernPenumbra->isChecked() ); 0400 m_settings.insert(QStringLiteral("showCentralLine"), 0401 m_configWidget->checkBoxShowCentralLine->isChecked() ); 0402 m_settings.insert(QStringLiteral("showFullPenumbra"), 0403 m_configWidget->checkBoxShowFullPenumbra->isChecked() ); 0404 m_settings.insert(QStringLiteral("show60MagPenumbra"), 0405 m_configWidget->checkBoxShow60MagPenumbra->isChecked() ); 0406 m_settings.insert(QStringLiteral("showSunBoundaries"), 0407 m_configWidget->checkBoxShowSunBoundaries->isChecked() ); 0408 0409 emit settingsChanged( nameId() ); 0410 } 0411 0412 void EclipsesPlugin::updateSettings() 0413 { 0414 if (!isInitialized()) { 0415 return; 0416 } 0417 0418 m_browserDialog->setWithLunarEclipses( 0419 m_settings.value(QStringLiteral("enableLunarEclipses")).toBool()); 0420 if( m_model->withLunarEclipses() != 0421 m_settings.value(QStringLiteral("enableLunarEclipses")).toBool()) { 0422 updateEclipses(); 0423 } 0424 } 0425 0426 void EclipsesPlugin::updateEclipses() 0427 { 0428 // mDebug() << "Updating eclipses...."; 0429 const int year = marbleModel()->clock()->dateTime().date().year(); 0430 const bool lun = m_settings.value(QStringLiteral("enableLunarEclipses")).toBool(); 0431 0432 if( ( m_menuYear != year ) || ( m_model->withLunarEclipses() != lun ) ) { 0433 0434 // remove old menus 0435 for( QAction *action: m_eclipsesListMenu->actions() ) { 0436 m_eclipsesListMenu->removeAction( action ); 0437 delete action; 0438 } 0439 0440 // update year and create menus for this year's eclipse events 0441 if( m_model->year() != year ) { 0442 m_model->setYear( year ); 0443 } 0444 m_menuYear = year; 0445 0446 // enable/disable lunar eclipses if necessary 0447 if( m_model->withLunarEclipses() != lun ) { 0448 m_model->setWithLunarEclipses( lun ); 0449 } 0450 0451 m_eclipsesListMenu->setTitle( tr("Eclipses in %1").arg( year ) ); 0452 0453 for( EclipsesItem *item: m_model->items() ) { 0454 QAction *action = m_eclipsesListMenu->addAction( 0455 item->dateMaximum().date().toString() ); 0456 action->setData( QVariant( 1000 * item->dateMaximum().date().year() + item->index() ) ); 0457 action->setIcon( item->icon() ); 0458 } 0459 0460 emit actionGroupsChanged(); 0461 } 0462 } 0463 0464 void EclipsesPlugin::updateMenuItemState() 0465 { 0466 if( !isInitialized() ) { 0467 return; 0468 } 0469 0470 // eclipses are only supported for earth based observers at the moment 0471 // so we disable the menu items for other celestial bodies 0472 0473 const bool active = (marbleModel()->planetId() == QLatin1String("earth")); 0474 0475 m_eclipsesListMenu->setEnabled( active ); 0476 m_eclipsesMenuAction->setEnabled( active ); 0477 } 0478 0479 void EclipsesPlugin::showEclipse( int year, int index ) 0480 { 0481 if( m_model->year() != year ) { 0482 m_model->setYear( year ); 0483 } 0484 0485 EclipsesItem *item = m_model->eclipseWithIndex( index ); 0486 Q_ASSERT( item ); 0487 0488 if( item ) { 0489 m_marbleWidget->model()->clock()->setDateTime( item->dateMaximum() ); 0490 m_marbleWidget->centerOn( item->maxLocation() ); 0491 } 0492 } 0493 0494 void EclipsesPlugin::showEclipseFromMenu( QAction *action ) 0495 { 0496 Q_ASSERT( action->data().isValid() ); 0497 int year = action->data().toInt() / 1000; 0498 int index = action->data().toInt() - 1000 * year; 0499 0500 showEclipse( year, index ); 0501 } 0502 0503 } // namespace Marble 0504 0505 #include "moc_EclipsesPlugin.cpp" 0506