[kstars] kstars: Introducing a new way of adding deep-sky objects into KStars

Akarsh Simha akarsh at kde.org
Thu Aug 18 09:35:24 UTC 2016


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: kstars-devel at kde.org
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                : akarsh.simha at kdemail.net
+***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   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 &regExp, 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                : akarsh.simha at kdemail.net
+***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   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 <akarsh at kde.org>
+ */
+
+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 &regExp, 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">


More information about the kde-doc-english mailing list