• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Stellarium / stellarium / 15670918640

16 Jun 2025 02:08AM UTC coverage: 11.775% (-0.2%) from 11.931%
15670918640

push

github

alex-w
Updated data

14700 of 124846 relevant lines covered (11.77%)

18324.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/plugins/OnlineQueries/src/OnlineQueries.cpp
1
/*
2
 * OnlineQueries plug-in for Stellarium
3
 *
4
 * Copyright (C) 2020-21 Georg Zotti
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18
 */
19

20
#include "StelApp.hpp"
21
#include "StelCore.hpp"
22
#include "StelModuleMgr.hpp"
23
#include "StelGui.hpp"
24
#include "StelGuiItems.hpp"
25
#include "StelObjectMgr.hpp"
26
#include "Star.hpp"
27
#include "StarMgr.hpp"
28
#include "Planet.hpp"
29
#include "NebulaMgr.hpp"
30
#include "Constellation.hpp"
31
#include "Asterism.hpp"
32
#include "StelDialog.hpp"
33
#include "OnlineQueries.hpp"
34
#include "OnlineQueriesDialog.hpp"
35

36
#include <QFontMetrics>
37
#include <QSettings>
38
#include <QMetaEnum>
39
#include <QLoggingCategory>
40
#include <QXmlStreamReader>
41
#include <stdexcept>
42

43
Q_LOGGING_CATEGORY(onlineQueries,"stel.plugin.OnlineQueries")
×
44

45
StelModule* OnlineQueriesPluginInterface::getStelModule() const
×
46
{
47
        return new OnlineQueries();
×
48
}
49

50
StelPluginInfo OnlineQueriesPluginInterface::getPluginInfo() const
×
51
{
52
        // Allow to load the resources when used as a static plugin
53
        Q_INIT_RESOURCE(OnlineQueries);
×
54

55
        StelPluginInfo info;
×
56
        info.id = "OnlineQueries";
×
57
        info.displayedName = N_("Online Queries");
×
58
        info.authors = "Georg Zotti, Alexander Wolf";
×
59
        info.contact = STELLARIUM_DEV_URL;
×
60
        info.description = N_("This plugin allows object information retrieval from selected online services.");
×
61
        info.version = ONLINEQUERIES_PLUGIN_VERSION;
×
62
        info.license = ONLINEQUERIES_PLUGIN_LICENSE;
×
63
        return info;
×
64
}
×
65

66
OnlineQueries::OnlineQueries() :
×
67
        enabled(false),
×
68
        disableWebView(false),
×
69
        toolbarButton(nullptr),
×
70
        custom1UseHip(false),
×
71
        custom2UseHip(false),
×
72
        custom3UseHip(false),
×
73
        hipQuery(nullptr),
×
74
        hipOnlineReply(nullptr)
×
75
{
76
        setObjectName("OnlineQueries");
×
77
        dialog = new OnlineQueriesDialog();
×
78
        StelApp &app = StelApp::getInstance();
×
79
        conf = app.getSettings();
×
80
}
×
81

82
OnlineQueries::~OnlineQueries()
×
83
{
84
        if (hipOnlineReply)
×
85
        {
86
                hipOnlineReply->deleteLater();
×
87
                hipOnlineReply = nullptr;
×
88
        }
89
        delete hipQuery;
×
90
        hipQuery=nullptr;
×
91
        delete dialog;
×
92
}
×
93

94
void OnlineQueries::init()
×
95
{
96
        if (!conf->childGroups().contains("OnlineQueries"))
×
97
        {
98
                qCDebug(onlineQueries) << "OnlineQueries: no section exists in main config file - creating with defaults";
×
99
                restoreDefaultConfiguration();
×
100
        }
101
        // populate settings from main config file.
102
        loadConfiguration();
×
103

104
        hipQuery=new HipOnlineQuery("");
×
105

106
        connect(StelApp::getInstance().getCore(), SIGNAL(configurationDataSaved()), this, SLOT(saveConfiguration()));
×
107
        addAction("actionShow_OnlineQueries",       N_("Online Queries"), N_("Show window for Online Queries"),           this, "enabled", "");
×
108
        addAction("actionShow_OnlineQueries_ASE",   N_("Online Queries"), N_("Call All Skies Encyclopaedia on current selection"),  this, "queryASE()", "");
×
109
        addAction("actionShow_OnlineQueries_AAVSO", N_("Online Queries"), N_("Call AAVSO database on current selection"), this, "queryAAVSO()", "");
×
110
        addAction("actionShow_OnlineQueries_GCVS",  N_("Online Queries"), N_("Call GCVS database on current selection"),  this, "queryGCVS()", "");
×
111
        addAction("actionShow_OnlineQueries_WP",    N_("Online Queries"), N_("Call Wikipedia on current selection"),      this, "queryWikipedia()", "");
×
112
        addAction("actionShow_OnlineQueries_C1",    N_("Online Queries"), N_("Call custom site 1 on current selection"),  this, "queryCustomSite1()", "");
×
113
        addAction("actionShow_OnlineQueries_C2",    N_("Online Queries"), N_("Call custom site 2 on current selection"),  this, "queryCustomSite2()", "");
×
114
        addAction("actionShow_OnlineQueries_C3",    N_("Online Queries"), N_("Call custom site 3 on current selection"),  this, "queryCustomSite3()", "");
×
115

116
        createToolbarButton();
×
117
}
×
118

119
void OnlineQueries::setEnabled(bool b)
×
120
{
121
        if (b!=enabled)
×
122
        {
123
                enabled = b;
×
124
                emit flagEnabledChanged(b);
×
125
                dialog->setVisible(b);
×
126
        }
127
}
×
128

129
bool OnlineQueries::configureGui(bool show)
×
130
{
131
        setEnabled(show);
×
132
        return true;
×
133
}
134

135
void OnlineQueries::restoreDefaultConfiguration(void)
×
136
{
137
        // Remove the whole section from the configuration file
138
        conf->remove("OnlineQueries");
×
139
        // Load the default values...
140
        loadConfiguration();
×
141
        // ... then save them.
142
        saveConfiguration();
×
143
}
×
144

145
void OnlineQueries::loadConfiguration(void)
×
146
{
147
        conf->beginGroup("OnlineQueries");
×
148

149
        disableWebView =conf->value("disable_webview", false).toBool();
×
150
        aseUrl         =conf->value("ase_url",          "https://xing.fmi.uni-jena.de/mediawiki/index.php/%1").toString();
×
151
        aavsoHipUrl    =conf->value("aavso_hip_url",    "https://www.aavso.org/vsx/index.php?view=api.object&ident=HIP%1").toString();
×
152
        aavsoOidUrl    =conf->value("aavso_oid_url",    "https://www.aavso.org/vsx/index.php?view=detail.top&oid=%1").toString();
×
153
        gcvsUrl        =conf->value("gcvs_url",         "http://www.sai.msu.su/gcvs/cgi-bin/ident.cgi?cat=Hip+&num=%1").toString();
×
154
        wikipediaUrl   =conf->value("wikipedia_url",    "https://en.wikipedia.org/wiki/%1").toString();
×
155
        customUrl1=conf->value("custom1_url", "").toString();
×
156
        if (!customUrl1.isEmpty() && !customUrl1.contains("%1"))
×
157
        {
158
                qWarning() << "OnlineQueries: custom1_url invalid: no '%1' found in " << customUrl1;
×
159
                customUrl1 = "";
×
160
        }
161
        customUrl2=conf->value("custom2_url", "").toString();
×
162
        if (!customUrl2.isEmpty() && !customUrl2.contains("%1"))
×
163
        {
164
                qWarning() << "OnlineQueries: custom2_url invalid: no '%1' found in " << customUrl2;
×
165
                customUrl2 = "";
×
166
        }
167
        customUrl3=conf->value("custom3_url", "").toString();
×
168
        if (!customUrl3.isEmpty() && !customUrl3.contains("%1"))
×
169
        {
170
                qWarning() << "OnlineQueries: custom3_url invalid: no '%1' found in " << customUrl3;
×
171
                customUrl3 = "";
×
172
        }
173
        custom1UseHip=conf->value("custom1_use_hip", true).toBool();
×
174
        custom2UseHip=conf->value("custom2_use_hip", true).toBool();
×
175
        custom3UseHip=conf->value("custom3_use_hip", true).toBool();
×
176
        conf->endGroup();
×
177
}
×
178

179
void OnlineQueries::saveConfiguration(void)
×
180
{
181
        conf->beginGroup("OnlineQueries");
×
182
        conf->setValue("ase_url", aseUrl);
×
183
        conf->setValue("aavso_hip_url", aavsoHipUrl);
×
184
        conf->setValue("aavso_oid_url", aavsoOidUrl);
×
185
        conf->setValue("gcvs_url", gcvsUrl);
×
186
        conf->setValue("wikipedia_url", wikipediaUrl);
×
187
        conf->setValue("custom1_url", customUrl1);
×
188
        conf->setValue("custom2_url", customUrl2);
×
189
        conf->setValue("custom3_url", customUrl3);
×
190
        conf->setValue("custom1_use_hip", custom1UseHip);
×
191
        conf->setValue("custom2_use_hip", custom2UseHip);
×
192
        conf->setValue("custom3_use_hip", custom3UseHip);
×
193
        conf->setValue("disable_webview", disableWebView);
×
194
        conf->endGroup();
×
195
}
×
196

197
void OnlineQueries::createToolbarButton() const
×
198
{
199
        // Add toolbar button (copy/paste widely from AngleMeasure).
200
        try
201
        {
202
                StelGui* gui = dynamic_cast<StelGui*>(StelApp::getInstance().getGui());
×
203

204
                if (gui!=nullptr)
×
205
                {
206
                        StelButton* button =        new StelButton(nullptr,
207
                                                               QPixmap(":/OnlineQueries/bt_OnlineQueries_On.png"),
×
208
                                                               QPixmap(":/OnlineQueries/bt_OnlineQueries_Off.png"),
×
209
                                                               QPixmap(":/graphicGui/miscGlow32x32.png"),
×
210
                                                               "actionShow_OnlineQueries");
×
211
                        //qCDebug(onlineQueries) << "adding Button to toolbar ...";
212

213
                        gui->getButtonBar()->addButton(button, "065-pluginsGroup");
×
214
                }
215
        }
216
        catch (std::runtime_error& e)
×
217
        {
218
                qCWarning(onlineQueries) << "Unable to create toolbar button for OnlineQueries plugin: " << e.what();
×
219
        }
×
220
}
×
221

222
void OnlineQueries::queryWikipedia()
×
223
{
224
        query(wikipediaUrl, false);
×
225
}
×
226

227
// 2-step query.
228
void OnlineQueries::queryAAVSO()
×
229
{
230
        setOutputHtml("<h1>AAVSO</h1><p>querying...</p>");
×
231

232
        const QList<StelObjectP>& sel=GETSTELMODULE(StelObjectMgr)->getSelectedObject();
×
233
        if (sel.length()==0)
×
234
                return;
×
235

236
        const StelObjectP obj=sel.at(0);
×
237
        if (obj->getType()!=STAR_TYPE)
×
238
                return;
×
239

240
        QString hipStr=obj->getID();
×
241
        if (!hipStr.startsWith("HIP"))
×
242
                return;
×
243

244
        int hipNr=hipStr.split(' ').at(1).toInt();
×
245
        hipOnlineReply=hipQuery->lookup(aavsoHipUrl, hipNr);
×
246

247
        // This only delivers the OID for the second AAVSO query
248
        onAavsoHipQueryStatusChanged();
×
249
        connect(hipOnlineReply, SIGNAL(statusChanged()), this, SLOT(onAavsoHipQueryStatusChanged()));
×
250
}
×
251

252
void OnlineQueries::queryGCVS()
×
253
{
254
        query(gcvsUrl, true);
×
255
}
×
256

257
void OnlineQueries::queryASE()
×
258
{
259
        setOutputHtml("<h1>All Skies Encyclopaedia</h1><p>querying...</p>");
×
260
        query(aseUrl, false);
×
261
}
×
262

263
void OnlineQueries::queryCustomSite1()
×
264
{
265
        query(customUrl1, custom1UseHip);
×
266
}
×
267

268
void OnlineQueries::queryCustomSite2()
×
269
{
270
        query(customUrl2, custom2UseHip);
×
271
}
×
272

273
void OnlineQueries::queryCustomSite3()
×
274
{
275
        query(customUrl3, custom3UseHip);
×
276
}
×
277

278
void OnlineQueries::query(const QString &url, bool useHip)
×
279
{
280
        // dissect url and set output.
281
        QUrl htmlUrl(url);
×
282
        setOutputHtml(QString("<h1>%1</h1><p>querying %2...</p>").arg(htmlUrl.host(), url));
×
283

284
        const QList<StelObjectP>& sel=GETSTELMODULE(StelObjectMgr)->getSelectedObject();
×
285
        if (sel.length()==0)
×
286
        {
287
                setOutputHtml(QString("<h1>%1</h1><p>%2</p>").arg(htmlUrl.host(), q_("Please select an object first!")));
×
288
                return;
×
289
        }
290
        const StelObjectP obj=sel.at(0);
×
291

292
        if (useHip)
×
293
        {
294
                if (obj->getType()!=STAR_TYPE)
×
295
                {
296
                        setOutputHtml(QString("<h1>%1</h1><p>%2</p>").arg(htmlUrl.host(), qc_("Not a star!", "OnlineQueries")));
×
297
                        return;
×
298
                }
299

300
                QString hipStr=obj->getID();
×
301
                if (!hipStr.startsWith("HIP"))
×
302
                {
303
                        setOutputHtml(QString("<h1>%1</h1><p>%2</p>").arg(htmlUrl.host(), qc_("Not a HIPPARCOS star!", "OnlineQueries")));
×
304
                        return;
×
305
                }
306
                int hipNr=hipStr.split(' ').at(1).toInt();
×
307
                setOutputUrl(QUrl(url.arg(hipNr)));
×
308
        }
×
309
        else
310
        {
311
                QString objName;
×
312
                if (obj->getType()==STAR_TYPE)
×
313
                {
314
                        QString hipStr=obj->getID();
×
315
                        if (!hipStr.startsWith("HIP"))
×
316
                        {
317
                                setOutputHtml(QString("<h1>%1</h1><p>%2</p>").arg(htmlUrl.host(), qc_("Not a HIPPARCOS star!", "OnlineQueries")));
×
318
                                return;
×
319
                        }
320
                        int hipNr=hipStr.split(' ').at(1).toInt();
×
321
                        objName=StarMgr::getCommonEnglishName(hipNr);
×
322
                }
×
323
                else if (obj->getType()==Planet::PLANET_TYPE)
×
324
                {
325
                        objName=obj->getEnglishName();
×
326
                }
327
                else if (obj->getType()==Nebula::NEBULA_TYPE)
×
328
                {
329
                        // clumsy workaround for uncastable pointer...
330
                        objName = GETSTELMODULE(NebulaMgr)->getLatestSelectedDSODesignation();
×
331
                        if (objName.isEmpty())
×
332
                        {
333
                                objName=obj->getEnglishName();
×
334
                        }
335
                        // WP has all Messiers and a few other catalogs with Messier_X and similar fuller names. Use those directly to avoid ambiguity.
336
                        // TODO: What to do with calls to non-Wikipedia sites with different spellings?
337
                        if (objName.startsWith("M "))
×
338
                                objName=objName.replace("M ", "Messier_");
×
339
                        else if (objName.startsWith("C "))
×
340
                                objName=objName.replace("C ", "Caldwell_");
×
341
                        else if (objName.startsWith("B "))
×
342
                                objName=objName.replace("B ", "Barnard_");
×
343
                        else if (objName.startsWith("Cr "))
×
344
                                objName=objName.replace("Cr ", "Collinder_");
×
345
                        else if (objName.startsWith("Mel "))
×
346
                                objName=objName.replace("Mel ", "Melotte_");
×
347
                        // TODO: Other similar replacements?
348
                        if (objName.isEmpty())
×
349
                        {
350
                                setOutputHtml(QString("<h1>%1</h1><p>%2</p>").arg(q_("ERROR"), q_("We can request data for stars, planets and deep-sky objects. A valid name for this object could not be found. Please enable a few DSO catalogs to form at least a numerical name.")));
×
351
                                return;
×
352
                        }
353
                }
354
                else if ((obj->getType()==Constellation::CONSTELLATION_TYPE) || (obj->getType()==Asterism::ASTERISM_TYPE))
×
355
                {
356
                        objName=obj->getEnglishName();
×
357
                }
358
                else
359
                {
360
                        setOutputHtml(QString("<h1>%1</h1><p>%2</p>").arg(q_("ERROR"), q_("We can request data for stars, constellations, asterisms, planets and deep-sky objects only.")));
×
361
                        return;
×
362
                }
363
                setOutputUrl(QUrl(url.arg(objName)));
×
364
        }
×
365
}
×
366

367
// Called when the current HIP query status changes. This displays simple HTML answers.
368
void OnlineQueries::onHipQueryStatusChanged()
×
369
{
370
        setEnabled(true); // show dialog
×
371
        Q_ASSERT(hipOnlineReply);
×
372
        if (hipOnlineReply->getCurrentStatus()==HipOnlineReply::HipQueryErrorOccured)
×
373
        {
374
                setOutputHtml(QString("<p>Lookup error: %1</p>").arg(hipOnlineReply->getErrorString()));
×
375
        }
376

377
        else if (hipOnlineReply->getCurrentStatus()==HipOnlineReply::HipQueryFinished)
×
378
        {
379
                setOutputHtml(hipOnlineReply->getResult());
×
380
        }
381

382
        else if (hipOnlineReply->getCurrentStatus()!=HipOnlineReply::HipQueryQuerying)
×
383
        {
384
                disconnect(hipOnlineReply, SIGNAL(statusChanged()), this, SLOT(onHipQueryStatusChanged()));
×
385
                delete hipOnlineReply;
×
386
                hipOnlineReply=nullptr;
×
387
        }
388
}
×
389

390
// Called when the current HIP query status changes. This displays simple HTML answers.
391
void OnlineQueries::onAavsoHipQueryStatusChanged()
×
392
{
393
        setEnabled(true); // show dialog
×
394
        Q_ASSERT(hipOnlineReply);
×
395
        if (hipOnlineReply->getCurrentStatus()==HipOnlineReply::HipQueryErrorOccured)
×
396
        {
397
                setOutputHtml(QString("<p>Lookup error: %1</p>").arg(hipOnlineReply->getErrorString()));
×
398
        }
399

400
        else if (hipOnlineReply->getCurrentStatus()==HipOnlineReply::HipQueryFinished)
×
401
        {
402
                //setOutputHtml(hipOnlineReply->getResult());
403
                // Parse XML, extract OID, lookup again.
404
                QXmlStreamReader xml(hipOnlineReply->getResult());
×
405
                int oid=0;
×
406
                while (!xml.atEnd()) {
×
407
                        xml.readNext();
×
408
                        if (xml.isStartElement() && xml.name()==QString("OID"))
×
409
                        {
410
                                oid=xml.readElementText().toInt();
×
411
                        }
412
                  }
413
                  if (xml.hasError()) {
×
414
                        qDebug() << "XML error in AAVSO's answer:" << xml.errorString();
×
415
                  }
416
                //qDebug() << "We have found OID=" << oid;
417

418
                //disconnect(hipOnlineReply, SIGNAL(statusChanged()), this, SLOT(onAavsoHipQueryStatusChanged()));
419
                //delete hipOnlineReply;
420

421
                // Trigger second AAVSO query. Note that we mangle the name a bit.
422
                if (oid>0)
×
423
                {
424
                        setOutputUrl(QUrl(aavsoOidUrl.arg(oid)));
×
425
                }
426
                else
427
                        setOutputHtml(QString("<h1>AAVSO</h1><p>AAVSO has no entry for this star.</p>"));
×
428
        }
×
429

430
        else if (hipOnlineReply->getCurrentStatus()!=HipOnlineReply::HipQueryQuerying)
×
431
        {
432
                disconnect(hipOnlineReply, SIGNAL(statusChanged()), this, SLOT(onAavsoHipQueryStatusChanged()));
×
433
                delete hipOnlineReply;
×
434
                hipOnlineReply=nullptr;
×
435
        }
436
}
×
437

438
void OnlineQueries::setOutputHtml(const QString &html)
×
439
{
440
        if (dialog)
×
441
                dialog->setOutputHtml(html);
×
442
}
×
443

444
void OnlineQueries::setOutputUrl(const QUrl &url)
×
445
{
446
        if (dialog)
×
447
                dialog->setOutputUrl(url);
×
448
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc