wiview.cpp 37.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/***************************************************************************
                          wiview.cpp  -  K Desktop Planetarium
                             -------------------
    begin                : 2012/26/05
    copyright            : (C) 2012 by Samikshan Bairagya
    email                : samikshan@gmail.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/
Csaba Kertesz's avatar
Csaba Kertesz committed
17 18 19 20

#include <QQuickView>
#include <QQuickItem>
#include <QQmlContext>
21 22
#include <QStandardPaths>
#include <QGraphicsObject>
23
#include "wiview.h"
24
#include "skymap.h"
25
#include "dialogs/detaildialog.h"
26
#include <klocalizedcontext.h>
27
#include "kspaths.h"
28
#include "starobject.h"
29 30 31 32
#include "skymap.h"
#include "Options.h"
#include "wiequipsettings.h"
#include "skymapcomposite.h"
33
#include <QtConcurrent>
34

35 36 37 38 39 40 41
#ifdef HAVE_INDI
#include <basedevice.h>
#include "indi/indilistener.h"
#include "indi/indistd.h"
#include "indi/driverinfo.h"
#endif

42
WIView::WIView(QWidget *parent) : QWidget(parent), m_CurrentObjectListName(-1)
43
{
44
    //These settings are like this just to get it started.
45 46 47
    int bortle                           = Options::bortleClass();
    int aperture                         = 100;
    ObsConditions::Equipment equip       = ObsConditions::Telescope;
48
    ObsConditions::TelescopeType telType = ObsConditions::Reflector;
49

50
    m_Obs = new ObsConditions(bortle, aperture, equip, telType);
51

52
    m_ModManager = new ModelManager(m_Obs);
53

54
    m_BaseView = new QQuickView();
55

56
    ///To use i18n() instead of qsTr() in qml/wiview.qml for translation
57
    //KDeclarative kd;
58
    // kd.setDeclarativeEngine(m_BaseView->engine());
59 60
    //kd.initialize();
    //kd.setupBindings();
61

62
    m_Ctxt = m_BaseView->rootContext();
63

64 65
    m_Ctxt->setContextProperty("soListModel",
                               m_ModManager->getTempModel()); // This is to avoid an error saying it doesn't exist.
66

67 68 69
    ///Use instead of KDeclarative
    m_Ctxt->setContextObject(new KLocalizedContext(m_BaseView));

Jasem Mutlaq's avatar
Jasem Mutlaq committed
70
    QString WI_Location;
71 72 73
#if defined(Q_OS_OSX)
    WI_Location = QCoreApplication::applicationDirPath() + "/../Resources/data/tools/whatsinteresting/qml/wiview.qml";
    if (!QFileInfo(WI_Location).exists())
74
        WI_Location = KSPaths::locate(QStandardPaths::AppDataLocation, "tools/whatsinteresting/qml/wiview.qml");
75 76 77 78 79
#elif defined(Q_OS_WIN)
    WI_Location = KSPaths::locate(QStandardPaths::GenericDataLocation, "tools/whatsinteresting/qml/wiview.qml");
#else
    WI_Location = KSPaths::locate(QStandardPaths::AppDataLocation, "tools/whatsinteresting/qml/wiview.qml");
#endif
80 81

    m_BaseView->setSource(QUrl::fromLocalFile(WI_Location));
82

83
    m_BaseObj = m_BaseView->rootObject();
84

85 86
    m_ProgressBar = m_BaseObj->findChild<QQuickItem *>("progressBar");

87 88
    m_loadingMessage = m_BaseObj->findChild<QQuickItem *>("loadingMessage");

89
    m_CategoryTitle = m_BaseObj->findChild<QQuickItem *>(QString("categoryTitle"));
90

91
    m_ViewsRowObj = m_BaseObj->findChild<QQuickItem *>(QString("viewsRowObj"));
92 93
    connect(m_ViewsRowObj, SIGNAL(categorySelected(QString)), this, SLOT(onCategorySelected(QString)));
    connect(m_ViewsRowObj, SIGNAL(inspectSkyObject(QString)), this, SLOT(inspectSkyObject(QString)));
94

95
    m_SoListObj = m_BaseObj->findChild<QQuickItem *>("soListObj");
96
    connect(m_SoListObj, SIGNAL(soListItemClicked(int)), this, SLOT(onSoListItemClicked(int)));
97

98
    m_DetailsViewObj = m_BaseObj->findChild<QQuickItem *>("detailsViewObj");
99

100 101 102
    descTextObj = m_DetailsViewObj->findChild<QObject *>("descTextObj");
    infoBoxText = m_DetailsViewObj->findChild<QObject *>("infoBoxText");

103
    m_skyObjView   = m_BaseObj->findChild<QQuickItem *>("skyObjView");
104 105
    m_ContainerObj = m_BaseObj->findChild<QQuickItem *>("containerObj");

106
    m_NextObj = m_BaseObj->findChild<QQuickItem *>("nextObj");
107
    connect(m_NextObj, SIGNAL(nextObjClicked()), this, SLOT(onNextObjClicked()));
108
    m_PrevObj = m_BaseObj->findChild<QQuickItem *>("prevObj");
109
    connect(m_PrevObj, SIGNAL(prevObjClicked()), this, SLOT(onPrevObjClicked()));
110

111 112
    m_CenterButtonObj = m_BaseObj->findChild<QQuickItem *>("centerButtonObj");
    connect(m_CenterButtonObj, SIGNAL(centerButtonClicked()), this, SLOT(onCenterButtonClicked()));
113

114
    autoCenterCheckbox = m_DetailsViewObj->findChild<QObject *>("autoCenterCheckbox");
115
    autoTrackCheckbox  = m_DetailsViewObj->findChild<QObject *>("autoTrackCheckbox");
116

117 118 119
    m_SlewTelescopeButtonObj = m_BaseObj->findChild<QQuickItem *>("slewTelescopeButtonObj");
    connect(m_SlewTelescopeButtonObj, SIGNAL(slewTelescopeButtonClicked()), this, SLOT(onSlewTelescopeButtonClicked()));

120
    m_DetailsButtonObj = m_BaseObj->findChild<QQuickItem *>("detailsButtonObj");
121 122
    connect(m_DetailsButtonObj, SIGNAL(detailsButtonClicked()), this, SLOT(onDetailsButtonClicked()));

123
    QObject *settingsIconObj = m_BaseObj->findChild<QQuickItem *>("settingsIconObj");
124 125
    connect(settingsIconObj, SIGNAL(settingsIconClicked()), this, SLOT(onSettingsIconClicked()));

126 127 128
    inspectIconObj = m_BaseObj->findChild<QQuickItem *>("inspectIconObj");
    connect(inspectIconObj, SIGNAL(inspectIconClicked(bool)), this, SLOT(onInspectIconClicked(bool)));

129 130 131 132 133 134
    visibleIconObj = m_BaseObj->findChild<QQuickItem *>("visibleIconObj");
    connect(visibleIconObj, SIGNAL(visibleIconClicked(bool)), this, SLOT(onVisibleIconClicked(bool)));

    favoriteIconObj = m_BaseObj->findChild<QQuickItem *>("favoriteIconObj");
    connect(favoriteIconObj, SIGNAL(favoriteIconClicked(bool)), this, SLOT(onFavoriteIconClicked(bool)));

135
    QObject *reloadIconObj = m_BaseObj->findChild<QQuickItem *>("reloadIconObj");
136 137
    connect(reloadIconObj, SIGNAL(reloadIconClicked()), this, SLOT(onReloadIconClicked()));

138
    QObject *downloadIconObj = m_BaseObj->findChild<QQuickItem *>("downloadIconObj");
139
    connect(downloadIconObj, SIGNAL(downloadIconClicked()), this, SLOT(onUpdateIconClicked()));
140

141
    m_BaseView->setResizeMode(QQuickView::SizeRootObjectToView);
142
    m_BaseView->show();
143

144 145 146 147 148 149 150
    // Fix some weird issue with what's interesting panel view under Windows
    // In Qt 5.9 it content is messed up and there is no way to close the panel
    #ifdef Q_OS_WIN
        m_BaseView->setFlags(Qt::WindowCloseButtonHint);
    #endif


151 152
    connect(KStars::Instance()->map(), SIGNAL(objectClicked(SkyObject *)), this,
            SLOT(inspectSkyObjectOnClick(SkyObject *)));
153 154

    manager = new QNetworkAccessManager();
155 156

    setProgressBarVisible(true);
157 158 159
    connect(m_ModManager, SIGNAL(loadProgressUpdated(double)), this, SLOT(updateProgress(double)));
    connect(m_ModManager, SIGNAL(modelUpdated()), this, SLOT(refreshListView()));
    m_ViewsRowObj->setProperty("enabled", false);
160

161 162
    inspectOnClick = false;

163
    nightVision = m_BaseObj->findChild<QObject *>("nightVision");
164 165
    if (Options::darkAppColors())
        nightVision->setProperty("state", "active");
166 167
}

Samikshan Bairagya's avatar
Samikshan Bairagya committed
168 169
WIView::~WIView()
{
170
    delete m_ModManager;
171
    delete m_CurSoItem;
172
    delete manager;
Samikshan Bairagya's avatar
Samikshan Bairagya committed
173
}
174

175 176 177 178
void WIView::setNightVisionOn(bool on)
{
    if (on)
        nightVision->setProperty("state", "active");
179
    else
180 181
        nightVision->setProperty("state", "");
    if (m_CurSoItem)
182 183 184
        loadDetailsView(m_CurSoItem, m_CurIndex);
}

185 186
void WIView::setProgressBarVisible(bool visible)
{
187 188 189
    m_ProgressBar->setProperty("visible", visible);
}

190 191
void WIView::updateProgress(double value)
{
192
    m_ProgressBar->setProperty("value", value);
193

194 195
    if (value == 1)
    {
196
        setProgressBarVisible(false);
197
        m_ViewsRowObj->setProperty("enabled", true);
198
        m_loadingMessage->setProperty("state", "");
199 200 201
    }
    else
    {
202 203
        setProgressBarVisible(true);
        m_loadingMessage->setProperty("state", "loading");
204 205 206
    }
}

207 208
void WIView::updateObservingConditions()
{
209
    int bortle = Options::bortleClass();
210

211 212 213 214 215 216
    /**
    NOTE This part of the code dealing with equipment type is presently not required
    as WI does not differentiate between Telescope and Binoculars. It only needs the
     aperture of the equipment whichever available. However this is kept as a part of
    the code as support to be utilised in the future.
    **/
217
    ObsConditions::Equipment equip = ObsConditions::None;
218

219 220 221 222 223 224
    if (Options::telescopeCheck() && Options::binocularsCheck())
        equip = ObsConditions::Both;
    else if (Options::telescopeCheck())
        equip = ObsConditions::Telescope;
    else if (Options::binocularsCheck())
        equip = ObsConditions::Binoculars;
225

226
    ObsConditions::TelescopeType telType;
227

228 229 230
    if (KStars::Instance()->getWIEquipSettings())
        telType = (equip == ObsConditions::Telescope) ? KStars::Instance()->getWIEquipSettings()->getTelType() :
                                                        ObsConditions::Invalid;
231 232
    else
        telType = ObsConditions::Invalid;
Rafal Kulaga's avatar
Rafal Kulaga committed
233

234
    int aperture = 100;
235

236 237 238
    //This doesn't work correctly, FIXME!!
    // if(KStars::Instance()->getWIEquipSettings())
    //    aperture = KStars::Instance()->getWIEquipSettings()->getAperture();
239

240 241 242 243
    if (!m_Obs)
        m_Obs = new ObsConditions(bortle, aperture, equip, telType);
    else
        m_Obs->setObsConditions(bortle, aperture, equip, telType);
244 245 246 247 248
}

void WIView::onCategorySelected(QString model)
{
    m_CurrentObjectListName = model;
249 250
    m_Ctxt->setContextProperty("soListModel", m_ModManager->returnModel(m_CurrentObjectListName));
    m_CurIndex = -2;
251 252 253 254 255 256 257
    if (!m_ModManager->showOnlyVisibleObjects())
        visibleIconObj->setProperty("state", "unchecked");
    if (!m_ModManager->showOnlyFavoriteObjects())
        favoriteIconObj->setProperty("state", "unchecked");
    if (model == "ngc" && (!m_ModManager->isNGCLoaded()))
    {
        QtConcurrent::run(m_ModManager, &ModelManager::loadNGCCatalog);
258 259
        return;
    }
260 261 262
    if (model == "ic" && (!m_ModManager->isICLoaded()))
    {
        QtConcurrent::run(m_ModManager, &ModelManager::loadICCatalog);
263 264
        return;
    }
265 266 267
    if (model == "sharpless" && (!m_ModManager->isSharplessLoaded()))
    {
        QtConcurrent::run(m_ModManager, &ModelManager::loadSharplessCatalog);
268 269
        return;
    }
Csaba Kertesz's avatar
Csaba Kertesz committed
270
    updateModel(*m_Obs);
271 272 273 274
}

void WIView::onSoListItemClicked(int index)
{
275 276
    SkyObjItem *soitem = m_ModManager->returnModel(m_CurrentObjectListName)->getSkyObjItem(index);
    if (soitem)
277
        loadDetailsView(soitem, index);
278 279
}

280
void WIView::onNextObjClicked()
281
{
282 283
    if (m_CurrentObjectListName != "")
    {
284
        int modelSize = m_ModManager->returnModel(m_CurrentObjectListName)->rowCount();
285 286 287
        SkyObjItem *nextItem =
            m_ModManager->returnModel(m_CurrentObjectListName)->getSkyObjItem((m_CurIndex + 1) % modelSize);
        loadDetailsView(nextItem, (m_CurIndex + 1) % modelSize);
288
    }
Samikshan Bairagya's avatar
Samikshan Bairagya committed
289
}
290 291 292

void WIView::onPrevObjClicked()
{
293 294
    if (m_CurrentObjectListName != "")
    {
295
        int modelSize = m_ModManager->returnModel(m_CurrentObjectListName)->rowCount();
296 297 298
        SkyObjItem *prevItem =
            m_ModManager->returnModel(m_CurrentObjectListName)->getSkyObjItem((m_CurIndex - 1 + modelSize) % modelSize);
        loadDetailsView(prevItem, (m_CurIndex - 1 + modelSize) % modelSize);
299
    }
300
}
301

302
void WIView::onCenterButtonClicked()
303
{
304
    ///Center map on selected sky-object
305 306
    SkyObject *so  = m_CurSoItem->getSkyObject();
    KStars *kstars = KStars::Instance();
307
    if (so)
308
    {
309 310 311
        kstars->map()->setFocusPoint(so);
        kstars->map()->setFocusObject(so);
        kstars->map()->setDestination(*kstars->map()->focusPoint());
312
        Options::setIsTracking(autoTrackCheckbox->property("checked") == true);
313 314
    }
}
315

316 317
void WIView::onSlewTelescopeButtonClicked()
{
318 319 320 321
    if (KMessageBox::Continue ==
        KMessageBox::warningContinueCancel(nullptr, "Are you sure you want your telescope to slew to this object?",
                                           i18n("Continue Slew"), KStandardGuiItem::cont(), KStandardGuiItem::cancel(),
                                           "continue_wi_slew_warning"))
322 323 324
    {
#ifdef HAVE_INDI

325
        if (INDIListener::Instance()->size() == 0)
326
        {
327
            KMessageBox::sorry(0, i18n("KStars did not find any active telescopes."));
328 329 330
            return;
        }

331 332 333
        foreach (ISD::GDInterface *gd, INDIListener::Instance()->getDevices())
        {
            INDI::BaseDevice *bd = gd->getBaseDevice();
334

335 336
            if (gd->getType() != KSTARS_TELESCOPE)
                continue;
337

338 339
            if (bd == nullptr)
                continue;
340

341 342 343 344 345 346
            if (bd->isConnected() == false)
            {
                KMessageBox::error(
                    0, i18n("Telescope %1 is offline. Please connect and retry again.", gd->getDeviceName()));
                return;
            }
347

348
            ISD::GDSetCommand SlewCMD(INDI_SWITCH, "ON_COORD_SET", "TRACK", ISS_ON, this);
349

350 351
            gd->setProperty(&SlewCMD);
            gd->runCommand(INDI_SEND_COORDS, m_CurSoItem->getSkyObject());
352

353 354
            ///Slew map to selected sky-object
            onCenterButtonClicked();
355

356 357
            return;
        }
358

359
        KMessageBox::sorry(0, i18n("KStars did not find any active telescopes."));
360

361 362
#endif
    }
363 364
}

365 366 367
void WIView::onDetailsButtonClicked()
{
    ///Code taken from WUTDialog::slotDetails()
368 369 370 371 372
    KStars *kstars = KStars::Instance();
    SkyObject *so  = m_CurSoItem->getSkyObject();
    if (so)
    {
        DetailDialog *detail = new DetailDialog(so, kstars->data()->lt(), kstars->data()->geo(), kstars);
373 374 375
        detail->exec();
        delete detail;
    }
376
}
377 378 379

void WIView::onSettingsIconClicked()
{
380
    KStars *kstars = KStars::Instance();
381
    kstars->showWISettingsUI();
382
}
383

384 385
void WIView::onReloadIconClicked()
{
386 387
    if (m_CurrentObjectListName != "")
    {
Csaba Kertesz's avatar
Csaba Kertesz committed
388
        updateModel(*m_Obs);
389
        m_CurIndex = m_ModManager->returnModel(m_CurrentObjectListName)->getSkyObjIndex(m_CurSoItem);
390
    }
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
    loadDetailsView(m_CurSoItem, m_CurIndex);
}

void WIView::onVisibleIconClicked(bool visible)
{
    m_ModManager->setShowOnlyVisibleObjects(visible);
    onReloadIconClicked();
}

void WIView::onFavoriteIconClicked(bool favorites)
{
    m_ModManager->setShowOnlyFavoriteObjects(favorites);
    onReloadIconClicked();
}

406 407
void WIView::onUpdateIconClicked()
{
408
    QMessageBox mbox;
409
    QPushButton *currentObject = mbox.addButton("Current Object", QMessageBox::AcceptRole);
Csaba Kertesz's avatar
Csaba Kertesz committed
410 411 412 413
    QPushButton *missingObjects = nullptr;
    QPushButton *allObjects = nullptr;

    mbox.setText("Please choose which object(s) to try to update with Wikipedia data.");
414 415 416 417 418 419
    if (m_CurrentObjectListName != "")
    {
        missingObjects = mbox.addButton("Objects with no data", QMessageBox::AcceptRole);
        allObjects     = mbox.addButton("Entire List", QMessageBox::AcceptRole);
    }
    QPushButton *cancel = mbox.addButton("Cancel", QMessageBox::AcceptRole);
420 421 422
    mbox.setDefaultButton(cancel);

    mbox.exec();
423
    if (mbox.clickedButton() == currentObject)
424
    {
425
        if (m_CurSoItem)
426 427 428 429
        {
            tryToUpdateWikipediaInfo(m_CurSoItem, getWikipediaName(m_CurSoItem));
        }
    }
430
    else if (mbox.clickedButton() == allObjects || mbox.clickedButton() == missingObjects)
431 432
    {
        SkyObjListModel *model = m_ModManager->returnModel(m_CurrentObjectListName);
433
        if (model->rowCount() > 0)
434
        {
435
            tryToUpdateWikipediaInfoInModel(mbox.clickedButton() == missingObjects);
436 437 438
        }
        else
        {
439
            qDebug() << "No Objects in List!";
440
        }
441
    }
442 443
}

444 445 446 447
void WIView::refreshListView()
{
    m_Ctxt->setContextProperty("soListModel", 0);
    if (m_CurrentObjectListName != "")
448
        m_Ctxt->setContextProperty("soListModel", m_ModManager->returnModel(m_CurrentObjectListName));
449
    if (m_CurIndex == -2)
450
        onSoListItemClicked(0);
451
    if (m_CurIndex != -1)
452 453 454
        m_SoListObj->setProperty("currentIndex", m_CurIndex);
}

Csaba Kertesz's avatar
Csaba Kertesz committed
455
void WIView::updateModel(ObsConditions& obs)
456
{
457 458
    if (m_CurrentObjectListName != "")
    {
Csaba Kertesz's avatar
Csaba Kertesz committed
459
        m_Obs = &obs;
460
        m_ModManager->updateModel(m_Obs, m_CurrentObjectListName);
461
    }
462 463
}

Csaba Kertesz's avatar
Csaba Kertesz committed
464
void WIView::inspectSkyObject(const QString& name)
465
{
Csaba Kertesz's avatar
Csaba Kertesz committed
466
    if (!name.isEmpty() && name != "star")
467 468
    {
        SkyObject *obj = KStarsData::Instance()->skyComposite()->findByName(name);
Csaba Kertesz's avatar
Csaba Kertesz committed
469

470
        if (obj)
471
            inspectSkyObject(obj);
472
    }
473 474
}

475 476 477
void WIView::inspectSkyObjectOnClick(SkyObject *obj)
{
    if (inspectOnClick && KStars::Instance()->isWIVisible())
478 479 480
        inspectSkyObject(obj);
}

481 482
void WIView::inspectSkyObject(SkyObject *obj)
{
Csaba Kertesz's avatar
Csaba Kertesz committed
483 484 485 486
    if (!obj)
        return;

    if (obj->name() != "star")
487
    {
Csaba Kertesz's avatar
Csaba Kertesz committed
488 489 490 491
        m_CurrentObjectListName = "";
        loadDetailsView(new SkyObjItem(obj), -1);
        m_BaseObj->setProperty("state", "singleItemSelected");
        m_CategoryTitle->setProperty("text", "Selected Object");
492
    }
493 494
}

495
void WIView::loadDetailsView(SkyObjItem *soitem, int index)
496
{
497
    if (!soitem)
498
        return;
Csaba Kertesz's avatar
Csaba Kertesz committed
499 500 501 502

    int modelSize = -1;

    if (index != -1)
503
        modelSize = m_ModManager->returnModel(m_CurrentObjectListName)->rowCount();
504

Csaba Kertesz's avatar
Csaba Kertesz committed
505 506
    m_CurSoItem = soitem;
    m_CurIndex  = index;
507
    if (modelSize <= 1)
Vijay Dhameliya's avatar
Vijay Dhameliya committed
508 509 510 511 512 513
    {
        m_NextObj->setProperty("visible", "false");
        m_PrevObj->setProperty("visible", "false");
    }
    else
    {
514 515 516 517
        SkyObjItem *nextItem =
            m_ModManager->returnModel(m_CurrentObjectListName)->getSkyObjItem((m_CurIndex + 1) % modelSize);
        SkyObjItem *prevItem =
            m_ModManager->returnModel(m_CurrentObjectListName)->getSkyObjItem((m_CurIndex - 1 + modelSize) % modelSize);
Csaba Kertesz's avatar
Csaba Kertesz committed
518

Vijay Dhameliya's avatar
Vijay Dhameliya committed
519 520
        m_NextObj->setProperty("visible", "true");
        m_PrevObj->setProperty("visible", "true");
521
        QObject *nextTextObj = m_NextObj->findChild<QObject *>("nextTextObj");
Csaba Kertesz's avatar
Csaba Kertesz committed
522

Vijay Dhameliya's avatar
Vijay Dhameliya committed
523
        nextTextObj->setProperty("text", nextItem->getName());
524
        QObject *prevTextObj = m_PrevObj->findChild<QObject *>("prevTextObj");
Csaba Kertesz's avatar
Csaba Kertesz committed
525

Vijay Dhameliya's avatar
Vijay Dhameliya committed
526 527
        prevTextObj->setProperty("text", prevItem->getName());
    }
528

529 530 531 532
    QObject *sonameObj      = m_DetailsViewObj->findChild<QObject *>("sonameObj");
    QObject *posTextObj     = m_DetailsViewObj->findChild<QObject *>("posTextObj");
    QObject *detailImage    = m_DetailsViewObj->findChild<QObject *>("detailImage");
    QObject *detailsTextObj = m_DetailsViewObj->findChild<QObject *>("detailsTextObj");
533

534
    sonameObj->setProperty("text", soitem->getDescName());
535
    posTextObj->setProperty("text", soitem->getPosition());
536
    detailImage->setProperty("refreshableSource", soitem->getImageURL(false));
537

538 539
    loadObjectDescription(soitem);

540 541 542
    infoBoxText->setProperty(
        "text",
        "<BR><BR>No Wikipedia information. <BR>  Please try to download it using the orange download button below.");
543
    loadObjectInfoBox(soitem);
544

545
    QString summary = soitem->getSummary(false);
546

547 548
    QString magText;
    if (soitem->getType() == SkyObjItem::Constellation)
Jasem Mutlaq's avatar
Jasem Mutlaq committed
549
        magText = xi18n("Magnitude:  --");
550
    else
551
        magText = xi18n("Magnitude: %1", QLocale().toString(soitem->getMagnitude(), 'f', 2));
552

Jasem Mutlaq's avatar
Jasem Mutlaq committed
553
    QString sbText = xi18n("Surface Brightness: %1", soitem->getSurfaceBrightness());
554

Jasem Mutlaq's avatar
Jasem Mutlaq committed
555
    QString sizeText = xi18n("Size: %1", soitem->getSize());
556

557
    QString details = summary + "<BR>" + sbText + "<BR>" + magText + "<BR>" + sizeText;
558 559
    detailsTextObj->setProperty("text", details);

560 561
    if (autoCenterCheckbox->property("checked") == true)
    {
562
        QTimer::singleShot(500, this, SLOT(onCenterButtonClicked()));
563 564
    }

565
    if (m_CurIndex != -1)
566
        m_SoListObj->setProperty("currentIndex", m_CurIndex);
567 568
}

569 570 571
QString WIView::getWikipediaName(SkyObjItem *soitem)
{
    if (!soitem)
572
        return "";
573
    QString name;
574 575 576 577 578 579 580 581
    if (soitem->getName().toLower().startsWith("m "))
        name = soitem->getName().replace("M ", "Messier_").remove(' ');
    else if (soitem->getName().toLower().startsWith("ngc"))
        name = soitem->getName().toLower().replace("ngc", "NGC_").remove(' ');
    else if (soitem->getName().toLower().startsWith("ic"))
        name = soitem->getName().toLower().replace("ic", "IC_").remove(' ');
    else if (soitem->getType() == SkyObjItem::Constellation)
    {
582
        QStringList words = soitem->getName().split(" ");
583 584 585 586 587
        for (int i = 0; i < words.size(); i++)
        {
            QString temp = words.at(i).toLower();
            temp[0]      = temp[0].toUpper();
            words.replace(i, temp);
588
        }
589 590
        name = words.join("_") + "_(constellation)";
        if (name.contains("Serpens"))
591
            name = "Serpens_(constellation)";
592
    }
593 594 595
    else if (soitem->getTypeName() == "Asteroid")
        name = soitem->getName().remove(' ') + "_(asteroid)";
    else if (soitem->getTypeName() == "Comet")
596
        name = soitem->getLongName();
597 598 599 600 601 602 603 604 605
    else if (soitem->getType() == SkyObjItem::Planet && soitem->getName() != "Sun" && soitem->getName() != "Moon")
        name = soitem->getName().remove(' ') + "_(planet)";
    else if (soitem->getType() == SkyObjItem::Star)
    {
        StarObject *star = dynamic_cast<StarObject *>(soitem->getSkyObject());
        name             = star->gname(false).replace(
            " ", "_"); //the greek name seems to give the most consistent search results for opensearch.
        if (name == "")
            name = soitem->getName().replace(" ", "_") + "_(star)";
606 607 608
        name.remove("[").remove("]");
    }
    else
609
        name = soitem->getName().remove(' ');
610 611
    return name;
}
612

613
void WIView::updateWikipediaDescription(SkyObjItem *soitem)
614
{
615
    if (!soitem)
616
        return;
617
    QString name = getWikipediaName(soitem);
618 619 620

    QUrl url("https://en.wikipedia.org/w/api.php?action=opensearch&search=" + name + "&format=xml");

621 622
    QNetworkReply *response = manager->get(QNetworkRequest(url));
    QTimer::singleShot(30000, response, [response] { //Shut it down after 30 sec.
623 624
        response->abort();
        response->deleteLater();
625
        qDebug() << "Wikipedia Download Timed out.";
626
    });
627 628 629 630 631 632 633 634 635 636 637 638 639 640 641
    connect(response, &QNetworkReply::finished, this, [soitem, this, response] {
        response->deleteLater();
        if (response->error() != QNetworkReply::NoError)
            return;
        QString contentType = response->header(QNetworkRequest::ContentTypeHeader).toString();
        if (!contentType.contains("charset=utf-8"))
        {
            qWarning() << "Content charsets other than utf-8 are not implemented yet.";
            return;
        }
        QString result = QString::fromUtf8(response->readAll());
        int leftPos    = result.indexOf("<Description") + 34;
        if (leftPos < 34)
            return;
        int rightPos = result.indexOf("</Description>") - leftPos;
642

643 644
        int leftURL  = result.indexOf("<Url xml:space=\"preserve\">") + 26;
        int rightURL = result.indexOf("</Url>") - leftURL;
645

646 647 648 649
        QString srchtml =
            "\n<p style=text-align:right>Source: (<a href='" + result.mid(leftURL, rightURL) + "'>" +
            "Wikipedia</a>)"; //Note the \n is so that the description is put on another line in the file.  Doesn't affect the display but allows the source to be loaded in the details but not the list.
        QString html = "<HTML>" + result.mid(leftPos, rightPos) + srchtml + "</HTML>";
650

651
        saveObjectInfoBoxText(soitem, "description", html);
652

653 654 655 656
        QString color     = (Options::darkAppColors()) ? "red" : "white";
        QString linkColor = (Options::darkAppColors()) ? "red" : "yellow";
        html              = "<HTML><HEAD><style type=text/css>body {color:" + color +
               ";} a {text-decoration: none;color:" + linkColor + ";}</style></HEAD><BODY>" + html + "</BODY></HTML>";
657

658 659 660
        if (soitem == m_CurSoItem)
            descTextObj->setProperty("text", html);
        refreshListView();
661
    });
662 663
}

664 665
void WIView::loadObjectDescription(SkyObjItem *soitem)
{
666
    QFile file;
667 668 669
    QString fname = "description-" + soitem->getName().toLower().remove(' ') + ".html";
    file.setFileName(KSPaths::writableLocation(QStandardPaths::GenericDataLocation) + "descriptions/" +
                     fname); //determine filename in local user KDE directory tree.
670

671 672 673
    if (file.exists())
    {
        if (file.open(QIODevice::ReadOnly))
674
        {
675
            QTextStream in(&file);
676
            QString color     = (Options::darkAppColors()) ? "red" : "white";
677
            QString linkColor = (Options::darkAppColors()) ? "red" : "yellow";
678 679 680
            QString line      = "<HTML><HEAD><style type=text/css>body {color:" + color +
                           ";} a {text-decoration: none;color:" + linkColor + ";}</style></HEAD><BODY><BR>" +
                           in.readAll() + "</BODY></HTML>";
681
            descTextObj->setProperty("text", line);
682
            file.close();
683
        }
684 685 686
    }
    else
    {
687
        descTextObj->setProperty("text", soitem->getTypeName());
688 689 690
    }
}

691
void WIView::loadObjectInfoBox(SkyObjItem *soitem)
692
{
693
    if (!soitem)
694
        return;
695
    QFile file;
696 697 698
    QString fname = "infoText-" + soitem->getName().toLower().remove(' ') + ".html";
    file.setFileName(KSPaths::writableLocation(QStandardPaths::GenericDataLocation) + "descriptions/" +
                     fname); //determine filename in local user KDE directory tree.
699

700
    if (file.exists())
701
    {
702
        if (file.open(QIODevice::ReadOnly))
703 704
        {
            QTextStream in(&file);
705
            QString infoBoxHTML;
706
            while (!in.atEnd())
707
            {
708
                infoBoxHTML = in.readAll();
709 710 711 712 713 714 715 716 717 718
                QString wikiImageName =
                    QUrl::fromLocalFile(
                        KSPaths::locate(QStandardPaths::GenericDataLocation,
                                        "descriptions/wikiImage-" + soitem->getName().toLower().remove(' ') + ".png"))
                        .url();
                if (wikiImageName != "")
                {
                    int captionEnd = infoBoxHTML.indexOf(
                        "</caption>"); //Start looking for the image AFTER the caption.  Planets have images in their caption.
                    if (captionEnd == -1)
719
                        captionEnd = 0;
720 721 722 723
                    int leftImg    = infoBoxHTML.indexOf("src=\"", captionEnd) + 5;
                    int rightImg   = infoBoxHTML.indexOf("\"", leftImg) - leftImg;
                    QString imgURL = infoBoxHTML.mid(leftImg, rightImg);
                    infoBoxHTML.replace(imgURL, wikiImageName);
724
                }
725
                QString color     = (Options::darkAppColors()) ? "red" : "white";
726
                QString linkColor = (Options::darkAppColors()) ? "red" : "yellow";
727 728 729 730 731
                if (Options::darkAppColors())
                    infoBoxHTML.replace("color: white", "color: " + color);
                infoBoxHTML = "<HTML><HEAD><style type=text/css>body {color:" + color +
                              ";} a {text-decoration: none;color:" + linkColor + ";}</style></HEAD><BODY>" +
                              infoBoxHTML + "</BODY></HTML>";
732

Robert Lancaster's avatar