Git commit 0a7cb3af6a92f02aac27438273ea170cfba995a5 by Akarsh Simha. Committed on 18/08/2016 at 09:36. Pushed by asimha into branch 'master'.
Introducing a new way of adding deep-sky objects into KStars 1. Create a new SyncedCatalogComponent catalog called "_Manual_Additions". This holds manually added DSOs that were not resolved from the internet. The concept is however the same -- it is a fake catalog for such custom added objects. 2. Build a UI for the purpose of manually introducing objects into this catalog. FEATURE: CCMAIL: [email protected] GUI: M +2 -0 kstars/CMakeLists.txt M +1 -0 kstars/data/kstarsui.rc M +1 -0 kstars/kstars.cpp M +6 -0 kstars/kstars.h M +9 -0 kstars/kstarsactions.cpp M +4 -0 kstars/kstarsinit.cpp M +18 -2 kstars/skycomponents/skymapcomposite.cpp M +3 -0 kstars/skycomponents/skymapcomposite.h A +293 -0 kstars/tools/adddeepskyobject.cpp [License: GPL (v2+)] A +80 -0 kstars/tools/adddeepskyobject.h [License: GPL (v2+)] M +95 -68 kstars/tools/adddeepskyobject.ui http://commits.kde.org/kstars/0a7cb3af6a92f02aac27438273ea170cfba995a5 diff --git a/kstars/CMakeLists.txt b/kstars/CMakeLists.txt index 6ef896d..aad4fe3 100644 --- a/kstars/CMakeLists.txt +++ b/kstars/CMakeLists.txt @@ -205,6 +205,7 @@ set(libkstarstools_SRCS tools/eyepiecefield.cpp tools/exporteyepieceview.cpp tools/starhopperdialog.cpp + tools/adddeepskyobject.cpp ) if(${KF5_VERSION} VERSION_EQUAL 5.18.0 OR ${KF5_VERSION} VERSION_GREATER 5.18.0) @@ -265,6 +266,7 @@ ki18n_wrap_ui(libkstarstools_SRCS tools/flagmanager.ui tools/starhopperdialog.ui tools/horizonmanager.ui + tools/adddeepskyobject.ui ) if (${KF5_VERSION} VERSION_EQUAL 5.18.0 OR ${KF5_VERSION} VERSION_GREATER 5.18.0) diff --git a/kstars/data/kstarsui.rc b/kstars/data/kstarsui.rc index c0821b7..153fdcb 100644 --- a/kstars/data/kstarsui.rc +++ b/kstars/data/kstarsui.rc @@ -87,6 +87,7 @@ <Action name="update_satellites" /> <Action name="update_supernovae" /> </Menu> + <Action name="manual_add_dso" /> </Menu> <Menu name="observation" noMerge="1"><text>&Observation</text> <Action name="obslist" /> diff --git a/kstars/kstars.cpp b/kstars/kstars.cpp index ef027f9..1c07051 100644 --- a/kstars/kstars.cpp +++ b/kstars/kstars.cpp @@ -66,6 +66,7 @@ KStars::KStars( bool doSplash, bool clockrun, const QString &startdate ) //#if 0 m_WIView(0), m_ObsConditions(0), m_wiDock(0), //#endif + m_addDSODialog(0), DialogIsObsolete(false), StartClockRunning( clockrun ), StartDateString( startdate ) { diff --git a/kstars/kstars.h b/kstars/kstars.h index af769d2..50cb7a0 100644 --- a/kstars/kstars.h +++ b/kstars/kstars.h @@ -58,6 +58,7 @@ class PrintingWizard; class EkosManager; class HorizonManager; class EyepieceField; +class AddDeepSkyObject; class OpsCatalog; class OpsGuides; @@ -469,6 +470,9 @@ public Q_SLOTS: /** Show the eyepiece view tool */ void slotEyepieceView( SkyPoint *sp, const QString &imagePath = QString() ); + /** Show the add deep-sky object dialog */ + void slotAddDeepSkyObject(); + private slots: /** action slot: open a dialog for setting the time and date */ @@ -683,6 +687,8 @@ private: EkosManager *m_EkosManager; #endif + AddDeepSkyObject *m_addDSODialog; + // FIXME Port to QML2 //#if 0 WIView *m_WIView; diff --git a/kstars/kstarsactions.cpp b/kstars/kstarsactions.cpp index c984c3c..c50afe2 100644 --- a/kstars/kstarsactions.cpp +++ b/kstars/kstarsactions.cpp @@ -80,6 +80,7 @@ #include "tools/wutdialog.h" #include "tools/observinglist.h" #include "tools/eyepiecefield.h" +#include "tools/adddeepskyobject.h" #ifdef HAVE_KF5WIT #include "tools/whatsinteresting/wiview.h" @@ -1486,3 +1487,11 @@ void KStars::slotUpdateSatellites() { data()->skyComposite()->satellites()->updateTLEs(); } + +void KStars::slotAddDeepSkyObject() { + if( ! m_addDSODialog ) { + Q_ASSERT( data() && data()->skyComposite() && data()->skyComposite()->manualAdditionsComponent() ); + m_addDSODialog = new AddDeepSkyObject( this, data()->skyComposite()->manualAdditionsComponent() ); + } + m_addDSODialog->show(); +} diff --git a/kstars/kstarsinit.cpp b/kstars/kstarsinit.cpp index 842b6fe..06939ef 100644 --- a/kstars/kstarsinit.cpp +++ b/kstars/kstarsinit.cpp @@ -356,6 +356,10 @@ void KStars::initActions() { << i18n("Startup Wizard..." ) << QIcon::fromTheme("tools-wizard" ); + // Manual data entry + actionCollection()->addAction( "manual_add_dso", this, SLOT( slotAddDeepSkyObject() ) ) + << i18n( "Manually add a deep-sky object" ); + // Updates actions actionCollection()->addAction( "update_comets", this, SLOT( slotUpdateComets() ) ) << i18n( "Update comets orbital elements" ); diff --git a/kstars/skycomponents/skymapcomposite.cpp b/kstars/skycomponents/skymapcomposite.cpp index 34488b8..412df2a 100644 --- a/kstars/skycomponents/skymapcomposite.cpp +++ b/kstars/skycomponents/skymapcomposite.cpp @@ -94,11 +94,13 @@ SkyMapComposite::SkyMapComposite(SkyComposite *parent ) : addComponent( m_ArtificialHorizon = new ArtificialHorizonComponent(this), 110); m_internetResolvedCat = "_Internet_Resolved"; + m_manualAdditionsCat = "_Manual_Additions"; addComponent( m_internetResolvedComponent = new SyncedCatalogComponent( this, m_internetResolvedCat, true, 0 ), 6 ); + addComponent( m_manualAdditionsComponent = new SyncedCatalogComponent( this, m_manualAdditionsCat, true, 0 ), 6 ); m_CustomCatalogs = new SkyComposite( this ); QStringList allcatalogs = Options::showCatalogNames(); for ( int i=0; i < allcatalogs.size(); ++ i ) { - if( allcatalogs.at(i) == m_internetResolvedCat ) // This is a special catalog + if( allcatalogs.at(i) == m_internetResolvedCat || allcatalogs.at(i) == m_manualAdditionsCat ) // This is a special catalog continue; m_CustomCatalogs->addComponent( new CatalogComponent( this, allcatalogs.at(i), false, i ), 6 // FIXME: Should this be 6 or 5? See SkyMapComposite::reloadDeepSky() @@ -150,6 +152,7 @@ void SkyMapComposite::update(KSNumbers *num ) //9. Custom catalogs m_CustomCatalogs->update( num ); m_internetResolvedComponent->update( num ); + m_manualAdditionsComponent->update( num ); //10. Stars //m_Stars->update( data, num ); //m_CLines->update( data, num ); // MUST follow stars. @@ -261,6 +264,7 @@ void SkyMapComposite::draw( SkyPainter *skyp ) m_CustomCatalogs->draw( skyp ); m_internetResolvedComponent->draw( skyp ); + m_manualAdditionsComponent->draw( skyp ); m_Stars->draw( skyp ); @@ -380,6 +384,14 @@ SkyObject* SkyMapComposite::objectNearest( SkyPoint *p, double &maxrad ) { } rTry = maxrad; + oTry = m_manualAdditionsComponent->objectNearest( p, rTry ); + rTry *= 0.5; + if ( rTry < rBest ) { + rBest = rTry; + oBest = oTry; + } + + rTry = maxrad; oTry = m_SolarSystem->objectNearest( p, rTry ); if( !dynamic_cast<KSComet *>( oTry ) && !dynamic_cast<KSAsteroid *>( oTry ) ) { // There are gazillions of faint asteroids and comets; we want to prevent them from getting precedence rTry *= 0.25; // this is either sun, moon, or one of the major planets or their moons. @@ -477,6 +489,8 @@ SkyObject* SkyMapComposite::findByName( const QString &name ) { if ( o ) return o; o = m_internetResolvedComponent->findByName( name ); if ( o ) return o; + o = m_manualAdditionsComponent->findByName( name ); + if ( o ) return o; o = m_CNames->findByName( name ); if ( o ) return o; o = m_Stars->findByName( name ); @@ -585,9 +599,11 @@ void SkyMapComposite::reloadDeepSky() { m_CustomCatalogs = new SkyComposite( this ); delete m_internetResolvedComponent; addComponent( m_internetResolvedComponent = new SyncedCatalogComponent( this, m_internetResolvedCat, true, 0 ), 6 ); + delete m_manualAdditionsComponent; + addComponent( m_manualAdditionsComponent = new SyncedCatalogComponent( this, m_manualAdditionsCat, true, 0 ), 6 ); QStringList allcatalogs = Options::showCatalogNames(); for ( int i=0; i < allcatalogs.size(); ++ i ) { - if( allcatalogs.at(i) == m_internetResolvedCat ) // This is a special catalog + if( allcatalogs.at(i) == m_internetResolvedCat || allcatalogs.at(i) == m_manualAdditionsCat ) // These are special catalogs continue; m_CustomCatalogs->addComponent( new CatalogComponent( this, allcatalogs.at(i), false, i ), 5 // FIXME: Should this be 6 or 5? See SkyMapComposite::SkyMapComposite() diff --git a/kstars/skycomponents/skymapcomposite.h b/kstars/skycomponents/skymapcomposite.h index a865436..6de619e 100644 --- a/kstars/skycomponents/skymapcomposite.h +++ b/kstars/skycomponents/skymapcomposite.h @@ -175,6 +175,7 @@ public: SupernovaeComponent* supernovaeComponent(); ArtificialHorizonComponent* artificialHorizon(); inline SyncedCatalogComponent* internetResolvedComponent() { return m_internetResolvedComponent; } + inline SyncedCatalogComponent* manualAdditionsComponent() { return m_manualAdditionsComponent; } //Accessors for StarComponent SkyObject* findStarByGenetiveName( const QString name ); @@ -231,6 +232,7 @@ private: SatellitesComponent *m_Satellites; SupernovaeComponent *m_Supernovae; SyncedCatalogComponent *m_internetResolvedComponent; + SyncedCatalogComponent *m_manualAdditionsComponent; SkyMesh* m_skyMesh; SkyLabeler* m_skyLabeler; @@ -243,6 +245,7 @@ private: QHash<int, QStringList> m_ObjectNames; QHash<QString, QString> m_ConstellationNames; QString m_internetResolvedCat; // Holds the name of the internet resolved catalog + QString m_manualAdditionsCat; }; #endif diff --git a/kstars/tools/adddeepskyobject.cpp b/kstars/tools/adddeepskyobject.cpp new file mode 100644 index 0000000..5b7bef4 --- /dev/null +++ b/kstars/tools/adddeepskyobject.cpp @@ -0,0 +1,293 @@ +/*************************************************************************** + adddeepskyobject.cpp - K Desktop Planetarium + ------------------- + begin : Wed 17 Aug 2016 20:22:58 CDT + copyright : (c) 2016 by Akarsh Simha + email : [email protected] +***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + + +/* Project Includes */ +#include "adddeepskyobject.h" + +/* KDE Includes */ +#include <KMessageBox> + +/* Qt Includes */ +#include <QInputDialog> + +AddDeepSkyObject::AddDeepSkyObject( QWidget *parent, SyncedCatalogComponent *catalog ) : + QDialog( parent ), m_catalog( catalog ), ui( new Ui::AddDeepSkyObject ) { + Q_ASSERT( catalog ); + ui->setupUi( this ); + + // Set up various things in the dialog so it is ready to be shown + for( int k = 0; k < SkyObject::NUMBER_OF_KNOWN_TYPES; ++k ) { + ui->typeComboBox->addItem( SkyObject::typeName( k ) ); + } + + ui->typeComboBox->addItem( SkyObject::typeName( SkyObject::TYPE_UNKNOWN ) ); + ui->catalogNameEdit->setEnabled( false ); + ui->catalogNameEdit->setText( catalog->name() ); + + resetView(); + + // Connections + // connect(ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(slotOk())); + QAbstractButton *resetButton = ui->buttonBox->button( QDialogButtonBox::Reset ); + connect( resetButton, SIGNAL( clicked() ), this, SLOT( resetView() ) ); + connect( ui->fillFromTextButton, SIGNAL( clicked() ), this, SLOT( slotFillFromText() ) ); + + // Show the UI + show(); +} + +AddDeepSkyObject::~AddDeepSkyObject() { + delete ui; +} + +void AddDeepSkyObject::fillFromText( const QString &text ) { + // Parse text to fill in the options + + // TODO: Add code to match and guess object type, to match blue magnitude. + + QRegularExpression matchJ2000Line( "^(.*)(?:J2000|ICRS|FK5|\\(2000(?:\\.0)?\\))(.*)$" ); + matchJ2000Line.setPatternOptions( QRegularExpression::MultilineOption ); + QRegularExpression matchCoords( "(?:^|[^-\\d])([-+]?\\d\\d?)(?:h ?|[^\\d]?° ?|:| +)(\\d\\d)(?:m ?|\' ?|:| +)(\\d\\d(?:\\.\\d+)?)(?:s|\"|\'\')?\\b" ); + QRegularExpression findMag1( "(?:[mM]ag(?:nitudes?)?|V(?=\\b))(?:\\s*=|:)?\\s*(-?\\d{1,2}(?:\\.\\d{1,3})?)" ); + QRegularExpression findMag2( "\\b-?\\d{1,2}(\\.\\d{1,3})?\\s*[mM]ag\\b"); + QRegularExpression findSize1( "\\b(\\d{1,3}(?:\\.\\d{1,2})?)\\s*(°|\'|\"|\'\')?\\s*[xX×]\\s*(\\d{1,3}(?:\\.\\d{1,2})?)\\s*(°|\'|\"|\'\')?\\b" ); + QRegularExpression findSize2( "\\b(?:[Ss]ize|[Dd]imensions?|[Dd]iameter)[: ](\\d{1,3}(?:\\.\\d{1,2})?)\\s*(°|\'|\"|\'\')?\\b" ); + QRegularExpression findMajorAxis( "\\b[Mm]ajor\\s*[Aa]xis:?\\s*(\\d{1,3}(?:\\.\\d{1,2})?)\\s*(°|\'|\"|\'\')?\\b" ); + QRegularExpression findMinorAxis( "\\b[Mm]inor\\s*[Aa]xis:?\\s*(\\d{1,3}(?:\\.\\d{1,2})?)\\s*(°|\'|\"|\'\')?\\b" ); + QRegularExpression findPA( "\\b(?:[Pp]osition *[Aa]ngle|PA|[pP]\\.[aA]\\.):?\\s*(\\d{1,3}(\\.\\d{1,2})?)(?:°|[Ddeg])?\\b" ); + QRegularExpression findName1( "\\b(?:[nN]ames?[: ]|[iI]dent(?:ifier)?:|[dD]esignation:)\\s*\"?([-+\'A-Za-z0-9 ]*)\"?\\b" ); + QStringList catalogNames; + catalogNames << "NGC" << "IC" << "M" << "PGC" << "UGC" << "MCG" << "ESO" << "SDSS" << "LEDA" + << "IRAS" << "PNG" << "Abell" << "ACO" << "HCG" << "CGCG" << "[IV]+Zw" << "Hickson" + << "AGC" << "2MASS" << "RCS2" << "Terzan" << "PN [A-Z0-9]" << "VV" << "PK" << "GSC2" + << "LBN" << "LDN" << "Caldwell" << "HIP" << "AM" << "vdB" << "B" << "Shk"; + QRegularExpression findName2( "\\b(" + catalogNames.join( "|" ) + ")\\s+(J?[-+0-9\\.]+[A-Da-h]?)\\b" ); + QRegularExpression findName3( "\\b([A-Za-z]+[0-9]?)\\s+(J?[-+0-9]+[A-Da-h]?)\\b" ); + + QString coordText = QString(); + bool coordsFound = false, magFound = false, sizeFound = false, nameFound = false, positionAngleFound = false; + dms RA, Dec; + float mag = NaN::f; + float majorAxis = NaN::f; + float minorAxis = NaN::f; + float positionAngle = 0; + QString name; + QRegularExpressionMatch rmatch; + if ( countNonOverlappingMatches( text, matchCoords ) == 2 ) { + coordText = text; + } + else if ( countNonOverlappingMatches( text, matchCoords ) > 2 ) { + qDebug() << "Found more than 2 coordinate matches. Trying to match J2000 line."; + if ( text.indexOf( matchJ2000Line, 0, &rmatch ) >= 0 ) { + coordText = rmatch.captured( 1 ) + rmatch.captured( 2 ); + qDebug() << "Found a J2000 line match: " << coordText; + if ( countNonOverlappingMatches( coordText, matchCoords ) != 2 ) + coordText = QString(); // Give up + } + } + if ( !coordText.isEmpty() ) { + int coord1 = coordText.indexOf( matchCoords, 0, &rmatch ); + Q_ASSERT( coord1 >= 0 ); + RA = dms( rmatch.captured( 1 ) + ' ' + rmatch.captured( 2 ) + ' ' + rmatch.captured( 3 ), false ); + int coord2 = coordText.indexOf( matchCoords, coord1 + rmatch.captured( 0 ).length(), &rmatch ); + Q_ASSERT( coord2 >= 0 ); + Dec = dms( rmatch.captured( 1 ) + ' ' + rmatch.captured( 2 ) + ' ' + rmatch.captured( 3 ), true ); + qDebug() << "Extracted coordinates: " << RA.toHMSString() << " " << Dec.toDMSString(); + coordsFound = true; + } + else { + QStringList matches; + qDebug() << "Could not extract RA/Dec. Found " << countNonOverlappingMatches( text, matchCoords, &matches ) << " coordinate matches:"; + qDebug() << matches; + } + + nameFound = true; + if ( text.contains( findName1, &rmatch ) ) { // Explicit name search + qDebug() << "Found explicit name field: " << rmatch.captured( 1 ) << " in text " << rmatch.captured( 0 ); + name = rmatch.captured( 1 ); + } + else if ( text.contains( findName2, &rmatch ) ) { + qDebug() << "Found known catalog field: " << ( name = rmatch.captured( 1 ) + ' ' + rmatch.captured( 2 ) ) << " in text " << rmatch.captured( 0 ); + } + else if ( text.contains( findName3, &rmatch ) ) { + qDebug() << "Found something that looks like a catalog designation: " << ( name = rmatch.captured( 1 ) + ' ' + rmatch.captured( 2 ) ) << " in text " << rmatch.captured( 0 ); + } + else { + qDebug() << "Could not find name."; + nameFound = false; + } + + magFound = true; + if ( text.contains( findMag1, &rmatch ) ) { + qDebug() << "Found magnitude: " << rmatch.captured( 1 ) << " in text " << rmatch.captured( 0 ); + mag = rmatch.captured( 1 ).toFloat(); + } + else if ( text.contains( findMag2, &rmatch ) ) { + qDebug() << "Found magnitude: " << rmatch.captured( 1 ) << " in text " << rmatch.captured( 0 ); + mag = rmatch.captured( 1 ).toFloat(); + } + else { + qDebug() << "Could not find magnitude."; + magFound = false; + } + + sizeFound = true; + if ( text.contains( findSize1, &rmatch ) ) { + qDebug() << "Found size: " << rmatch.captured( 1 ) << " x " << rmatch.captured( 3 ) << " with units " << rmatch.captured( 4 ) << " in text " << rmatch.captured( 0 ); + majorAxis = rmatch.captured( 1 ).toFloat(); + QString unitText2; + if ( rmatch.captured( 2 ).isEmpty() ) { + unitText2 = rmatch.captured( 4 ); + } + else { + unitText2 = rmatch.captured( 2 ); + } + + if ( unitText2.contains( "°" ) ) + majorAxis *= 60; + else if ( unitText2.contains( "\"" ) || unitText2.contains( "\'\'" ) ) + majorAxis /= 60; + + minorAxis = rmatch.captured( 3 ).toFloat(); + if ( rmatch.captured( 4 ).contains( "°" ) ) + minorAxis *= 60; + else if ( rmatch.captured( 4 ).contains( "\"" ) || rmatch.captured( 4 ).contains( "\'\'" ) ) + minorAxis /= 60; + qDebug() << "Major axis = " << majorAxis << "; minor axis = " << minorAxis << " in arcmin"; + } + else if ( text.contains( findSize2, &rmatch ) ) { + majorAxis = rmatch.captured( 1 ).toFloat(); + if ( rmatch.captured( 2 ).contains( "°" ) ) + majorAxis *= 60; + else if ( rmatch.captured( 2 ).contains( "\"" ) || rmatch.captured( 2 ).contains( "\'\'" ) ) + majorAxis /= 60; + minorAxis = majorAxis; + } + else if ( text.contains( findMajorAxis, &rmatch ) ) { + majorAxis = rmatch.captured( 1 ).toFloat(); + if ( rmatch.captured( 2 ).contains( "°" ) ) + majorAxis *= 60; + else if ( rmatch.captured( 2 ).contains( "\"" ) || rmatch.captured( 2 ).contains( "\'\'" ) ) + majorAxis /= 60; + minorAxis = majorAxis; + if ( text.contains( findMinorAxis, &rmatch ) ) { + minorAxis = rmatch.captured( 1 ).toFloat(); + if ( rmatch.captured( 2 ).contains( "°" ) ) + minorAxis *= 60; + else if ( rmatch.captured( 2 ).contains( "\"" ) || rmatch.captured( 2 ).contains( "\'\'" ) ) + minorAxis /= 60; + } + } + + + else { + qDebug() << "Could not find size."; // FIXME: Improve to include separate major and minor axis matches, and size matches for round objects. + sizeFound = false; + } + + positionAngleFound = true; + if ( text.contains( findPA, &rmatch ) ) { + qDebug() << "Found position angle: " << rmatch.captured( 1 ) << " in text " << rmatch.captured( 0 ); + positionAngle = rmatch.captured( 1 ).toFloat(); + } + else { + qDebug() << "Could not find position angle."; + positionAngleFound = false; + } + + if ( nameFound ) + ui->longNameEdit->setText( name ); + if ( magFound ) + ui->visualMagnitudeInput->setValue( mag ); // Improve band identification (V vs. B) + if ( coordsFound ) { + ui->raInput->setDMS( RA.toHMSString() ); + ui->decInput->setDMS( Dec.toDMSString() ); + } + if ( positionAngleFound ) + ui->positionAngleInput->setValue( positionAngle ); + if ( sizeFound ) { + ui->majorAxisInput->setValue( majorAxis ); + ui->minorAxisInput->setValue( minorAxis ); + } +} + +void AddDeepSkyObject::resetView() { + ui->actualTypeDisplay->setText( SkyObject::typeName( SkyObject::TYPE_UNKNOWN ) ); + ui->catalogIDInput->setValue( m_catalog->objectList().count() ); + ui->blueMagnitudeInput->setValue( 99.99 ); + ui->visualMagnitudeInput->setValue( 99.99 ); + ui->typeComboBox->setCurrentIndex( ui->typeComboBox->count() - 1 ); + ui->majorAxisInput->setValue( 0.0 ); + ui->minorAxisInput->setValue( 0.0 ); + ui->positionAngleInput->setValue( 0.0 ); + ui->longNameEdit->setText( QString() ); + ui->raInput->setDMS( QString() ); + ui->decInput->setDMS( QString() ); +} + +bool AddDeepSkyObject::slotOk() { + // Formulate a CatalogEntryData object + CatalogEntryData centry; + bool ok; + + centry.magnitude = ui->visualMagnitudeInput->value(); + centry.flux = ui->blueMagnitudeInput->value(); + centry.ra = ui->raInput->createDms( false, &ok ).Degrees(); + centry.dec = ui->decInput->createDms( true, &ok ).Degrees(); + centry.major_axis = ui->majorAxisInput->value(); + centry.minor_axis = ui->minorAxisInput->value(); + centry.long_name = ui->longNameEdit->text(); + centry.type = ui->typeComboBox->currentIndex(); + centry.position_angle = ui->positionAngleInput->value(); + if( centry.type == ui->typeComboBox->count() - 1 ) + centry.type = SkyObject::TYPE_UNKNOWN; + + // Insert it into the catalog + bool success = m_catalog->addObject( centry ); + + if( !success ) { + // Display error message + KMessageBox::sorry( 0, i18n( "Could not add deep-sky object. See console for error message!" ), i18n( "Add deep-sky object" ) ); + } + // Accept the dialog + + return success; +} + +void AddDeepSkyObject::slotFillFromText() { + bool ok = false; + QString text = QInputDialog::getMultiLineText( this, i18n( "Add deep-sky object : enter text" ), + i18n( "Enter the data to guess parameters from:" ), QString(), &ok ); + if ( ok ) + fillFromText( text ); +} + +int AddDeepSkyObject::countNonOverlappingMatches( const QString &string, const QRegularExpression ®Exp, QStringList *list ) { + int count = 0; + int matchIndex = -1; + int lastMatchLength = 1; + QRegularExpressionMatch rmatch; + while ( ( matchIndex = string.indexOf( regExp, matchIndex + lastMatchLength, &rmatch ) ) >= 0 ) { + ++count; + lastMatchLength = rmatch.captured( 0 ).length(); + if ( list ) + list->append( rmatch.captured( 0 ) ); + } + return count; +} diff --git a/kstars/tools/adddeepskyobject.h b/kstars/tools/adddeepskyobject.h new file mode 100644 index 0000000..fa0ceec --- /dev/null +++ b/kstars/tools/adddeepskyobject.h @@ -0,0 +1,80 @@ +/*************************************************************************** + adddeepskyobject.h - K Desktop Planetarium + ------------------- + begin : Wed 17 Aug 2016 20:23:05 CDT + copyright : (c) 2016 by Akarsh Simha + email : [email protected] +***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + + + +#ifndef ADDDEEPSKYOBJECT_H +#define ADDDEEPSKYOBJECT_H + +#include "ui_adddeepskyobject.h" +#include "syncedcatalogcomponent.h" +#include <QString> +#include <QRegularExpression> + +/** + * @class AddDeepSkyObject + * @short Allows the user to add an object to a @sa SyncedCatalogComponent + * @author Akarsh Simha <[email protected]> + */ + +class AddDeepSkyObject : public QDialog, public Ui::AddDeepSkyObject { + + Q_OBJECT; + + public: + + /** + * @short Constructor + */ + AddDeepSkyObject( QWidget *parent, SyncedCatalogComponent *catalog ); + + /** + * @short Destructor + */ + ~AddDeepSkyObject(); + + /** + * @short Fills the dialog from a text by trying to guess fields + */ + void fillFromText( const QString &text ); + + public slots: + + /** + * @short Accept the dialog and add the entry to the catalog + */ + bool slotOk(); + + /** + * @short Resets the entries in the dialog + */ + void resetView(); + + /** + * @short Gathers the text and calls fillFromText() to parse the text + */ + void slotFillFromText(); + + private: + + int countNonOverlappingMatches( const QString &string, const QRegularExpression ®Exp, QStringList *list = 0 ); + + SyncedCatalogComponent *m_catalog; + Ui::AddDeepSkyObject *ui; +}; + +#endif diff --git a/kstars/tools/adddeepskyobject.ui b/kstars/tools/adddeepskyobject.ui index 64fee79..3e8705a 100644 --- a/kstars/tools/adddeepskyobject.ui +++ b/kstars/tools/adddeepskyobject.ui @@ -1,41 +1,25 @@ <?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> - <class>Dialog</class> - <widget class="QDialog" name="Dialog"> + <class>AddDeepSkyObject</class> + <widget class="QDialog" name="AddDeepSkyObject"> <property name="geometry"> <rect> <x>0</x> <y>0</y> - <width>708</width> - <height>468</height> + <width>703</width> + <height>470</height> </rect> </property> <property name="windowTitle"> <string>Add/Edit Deep Sky Object</string> </property> - <widget class="QDialogButtonBox" name="buttonBox"> - <property name="geometry"> - <rect> - <x>350</x> - <y>430</y> - <width>341</width> - <height>32</height> - </rect> - </property> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="standardButtons"> - <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> - </property> - </widget> <widget class="QGroupBox" name="groupBox"> <property name="geometry"> <rect> <x>10</x> <y>10</y> <width>681</width> - <height>150</height> + <height>115</height> </rect> </property> <property name="sizePolicy"> @@ -47,7 +31,7 @@ <property name="minimumSize"> <size> <width>0</width> - <height>150</height> + <height>115</height> </size> </property> <property name="title"> @@ -63,19 +47,6 @@ </rect> </property> <layout class="QGridLayout" name="gridLayout"> - <item row="1" column="3"> - <widget class="QComboBox" name="catalogComboBox"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="editable"> - <bool>true</bool> - </property> - </widget> - </item> <item row="3" column="3" colspan="3"> <widget class="QLineEdit" name="longNameEdit"/> </item> @@ -88,7 +59,7 @@ </sizepolicy> </property> <property name="text"> - <string>Numeric ID*:</string> + <string>Numeric ID:</string> </property> <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> @@ -113,11 +84,17 @@ </item> <item row="1" column="5"> <widget class="QSpinBox" name="catalogIDInput"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="minimum"> + <number>-1</number> + </property> <property name="maximum"> <number>99999999</number> </property> <property name="value"> - <number>1</number> + <number>-1</number> </property> </widget> </item> @@ -150,36 +127,33 @@ </property> </widget> </item> + <item row="1" column="3"> + <widget class="QLineEdit" name="catalogNameEdit"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> </layout> </widget> - <widget class="QLabel" name="label_4"> - <property name="geometry"> - <rect> - <x>20</x> - <y>100</y> - <width>631</width> - <height>41</height> - </rect> - </property> - <property name="text"> - <string>*As of this version the primary designation necessarily has to have a catalog and a unique numeric ID with no suffix. As a workaround when needed, consider using alternate designations, or create fake catalogs of miscellaneous objects, and use the long name to include the designation of your choice.</string> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> </widget> <widget class="QGroupBox" name="groupBox_2"> <property name="geometry"> <rect> <x>10</x> - <y>170</y> + <y>130</y> <width>461</width> - <height>91</height> + <height>111</height> </rect> </property> <property name="title"> - <string>Coordinates (J2000)</string> + <string>Coordinates (J2000 / ICRS)</string> </property> <widget class="QWidget" name="horizontalLayoutWidget"> <property name="geometry"> @@ -205,7 +179,7 @@ </widget> </item> <item> - <widget class="dmsBox" name="raInput" native="true"/> + <widget class="dmsBox" name="raInput"/> </item> <item> <widget class="QLabel" name="label_6"> @@ -224,7 +198,7 @@ </widget> </item> <item> - <widget class="dmsBox" name="decInput" native="true"/> + <widget class="dmsBox" name="decInput"/> </item> </layout> </widget> @@ -233,7 +207,7 @@ <property name="geometry"> <rect> <x>310</x> - <y>270</y> + <y>250</y> <width>381</width> <height>101</height> </rect> @@ -247,7 +221,7 @@ <x>20</x> <y>30</y> <width>341</width> - <height>61</height> + <height>70</height> </rect> </property> <layout class="QHBoxLayout" name="horizontalLayout_2"> @@ -342,9 +316,9 @@ <property name="geometry"> <rect> <x>480</x> - <y>170</y> + <y>130</y> <width>211</width> - <height>91</height> + <height>111</height> </rect> </property> <property name="title"> @@ -413,7 +387,7 @@ <property name="geometry"> <rect> <x>10</x> - <y>270</y> + <y>250</y> <width>291</width> <height>101</height> </rect> @@ -427,7 +401,7 @@ <x>20</x> <y>30</y> <width>251</width> - <height>61</height> + <height>68</height> </rect> </property> <layout class="QFormLayout" name="formLayout_2"> @@ -472,7 +446,7 @@ <property name="geometry"> <rect> <x>10</x> - <y>380</y> + <y>360</y> <width>681</width> <height>31</height> </rect> @@ -488,7 +462,7 @@ <property name="geometry"> <rect> <x>10</x> - <y>410</y> + <y>400</y> <width>681</width> <height>16</height> </rect> @@ -497,13 +471,66 @@ <string>** Major and minor axes are in arcminutes, position angle is in degrees.</string> </property> </widget> + <widget class="QWidget" name="horizontalLayoutWidget_3"> + <property name="geometry"> + <rect> + <x>10</x> + <y>420</y> + <width>681</width> + <height>41</height> + </rect> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <widget class="QPushButton" name="fillFromTextButton"> + <property name="text"> + <string>Guess from &Text</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <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="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Reset</set> + </property> + <property name="centerButtons"> + <bool>false</bool> + </property> + </widget> + </item> + </layout> + </widget> </widget> + <customwidgets> + <customwidget> + <class>dmsBox</class> + <extends>QLineEdit</extends> + <header>widgets/dmsbox.h</header> + <container>1</container> + </customwidget> + </customwidgets> <resources/> <connections> <connection> <sender>buttonBox</sender> <signal>accepted()</signal> - <receiver>Dialog</receiver> + <receiver>AddDeepSkyObject</receiver> <slot>accept()</slot> <hints> <hint type="sourcelabel"> @@ -519,7 +546,7 @@ <connection> <sender>buttonBox</sender> <signal>rejected()</signal> - <receiver>Dialog</receiver> + <receiver>AddDeepSkyObject</receiver> <slot>reject()</slot> <hints> <hint type="sourcelabel">
