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

Stellarium / stellarium / 6685397774

29 Oct 2023 07:37PM UTC coverage: 11.735% (-0.002%) from 11.737%
6685397774

push

github

10110111
Deduplicate title bar implementation

131 of 131 new or added lines in 56 files covered. (100.0%)

14842 of 126472 relevant lines covered (11.74%)

21617.74 hits per line

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

0.0
/plugins/SolarSystemEditor/src/gui/MpcImportWindow.cpp
1
/*
2
 * Solar System editor plug-in for Stellarium
3
 *
4
 * Copyright (C) 2010 Bogdan Marinov
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, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335, USA.
19
 */
20

21
#include "SolarSystemEditor.hpp"
22

23
#include "MpcImportWindow.hpp"
24
#include "ui_mpcImportWindow.h"
25

26
#include "StelApp.hpp"
27
#include "StelFileMgr.hpp"
28
#include "StelMainView.hpp"
29
#include "StelJsonParser.hpp"
30
#include "StelModuleMgr.hpp"
31
#include "StelTranslator.hpp"
32
#include "SolarSystem.hpp"
33
#include "StelProgressController.hpp"
34
#include "SearchDialog.hpp"
35
#include "StelUtils.hpp"
36

37
#include <QGuiApplication>
38
#include <QClipboard>
39
#include <QDesktopServices>
40
#include <QFileDialog>
41
#include <QSortFilterProxyModel>
42
#include <QHash>
43
#include <QList>
44
#include <QNetworkAccessManager>
45
#include <QNetworkRequest>
46
#include <QNetworkReply>
47
#include <QStandardItemModel>
48
#include <QString>
49
#include <QTemporaryFile>
50
#include <QTimer>
51
#include <QUrl>
52
#include <QUrlQuery>
53
#include <QDir>
54
#include <QRegularExpression>
55
#include <stdexcept>
56

57
MpcImportWindow::MpcImportWindow()
×
58
        : StelDialog("SolarSystemEditorMPCimport")
59
        , filterProxyModel(nullptr)
×
60
        , importType(ImportType())
×
61
        , downloadReply(nullptr)
×
62
        , queryReply(nullptr)
×
63
        , downloadProgressBar(nullptr)
×
64
        , queryProgressBar(nullptr)
×
65
        , countdown(0)
×
66
{
67
        ui = new Ui_mpcImportWindow();
×
68
        ssoManager = GETSTELMODULE(SolarSystemEditor);
×
69

70
        //networkManager = StelApp::getInstance().getNetworkAccessManager();
71
        networkManager = new QNetworkAccessManager(this);
×
72

73
        countdownTimer = new QTimer(this);
×
74

75
        QHash<QString,QString> asteroidBookmarks;
×
76
        QHash<QString,QString> cometBookmarks;
×
77
        bookmarks.insert(MpcComets, cometBookmarks);
×
78
        bookmarks.insert(MpcMinorPlanets, asteroidBookmarks);
×
79

80
        candidateObjectsModel = new QStandardItemModel(this);
×
81
}
×
82

83
MpcImportWindow::~MpcImportWindow()
×
84
{
85
        delete ui;
×
86
        delete countdownTimer;
×
87
        candidateObjectsModel->clear();
×
88
        delete candidateObjectsModel;
×
89
        if (downloadReply)
×
90
                downloadReply->deleteLater();
×
91
        if (queryReply)
×
92
                queryReply->deleteLater();
×
93
        if (downloadProgressBar)
×
94
                StelApp::getInstance().removeProgressBar(downloadProgressBar);
×
95
        if (queryProgressBar)
×
96
                StelApp::getInstance().removeProgressBar(queryProgressBar);
×
97
}
×
98

99
void MpcImportWindow::createDialogContent()
×
100
{
101
        ui->setupUi(dialog);
×
102

103
        //Signals
104
        connect(&StelApp::getInstance(), SIGNAL(languageChanged()), this, SLOT(retranslate()));
×
105
        connect(ui->titleBar,            &TitleBar::closeClicked,   this, &StelDialog::close);
×
106
        connect(ui->titleBar,            SIGNAL(movedTo(QPoint)),   this, SLOT(handleMovedTo(QPoint)));
×
107

108
        connect(ui->pushButtonAcquire,       SIGNAL(clicked()), this, SLOT(acquireObjectData()));
×
109
        connect(ui->pushButtonAbortDownload, SIGNAL(clicked()), this, SLOT(abortDownload()));
×
110
        connect(ui->pushButtonAdd,           SIGNAL(clicked()), this, SLOT(addObjects()));
×
111
        connect(ui->pushButtonDiscard,       SIGNAL(clicked()), this, SLOT(discardObjects()));
×
112

113
        connect(ui->pushButtonBrowse,        SIGNAL(clicked()), this, SLOT(selectFile()));
×
114
        connect(ui->comboBoxBookmarks,       SIGNAL(currentIndexChanged(int)),this, SLOT(bookmarkSelected(int)));
×
115

116
        connect(ui->radioButtonFile,         SIGNAL(toggled(bool)), ui->frameFile, SLOT(setVisible(bool)));
×
117
        connect(ui->radioButtonURL,          SIGNAL(toggled(bool)), ui->frameURL,  SLOT(setVisible(bool)));
×
118

119
        connect(ui->radioButtonAsteroids,    SIGNAL(toggled(bool)), this, SLOT(switchImportType(bool)));
×
120
        connect(ui->radioButtonComets,       SIGNAL(toggled(bool)), this, SLOT(switchImportType(bool)));
×
121

122
        connect(ui->pushButtonMarkAll,       SIGNAL(clicked()), this, SLOT(markAll()));
×
123
        connect(ui->pushButtonMarkNone,      SIGNAL(clicked()), this, SLOT(unmarkAll()));
×
124

125
        connect(ui->pushButtonSendQuery,     SIGNAL(clicked()),           this, SLOT(sendQuery()));
×
126
        connect(ui->lineEditQuery,           SIGNAL(returnPressed()),     this, SLOT(sendQuery()));
×
127
        connect(ui->pushButtonAbortQuery,    SIGNAL(clicked()),           this, SLOT(abortQuery()));
×
128
        connect(ui->lineEditQuery,           SIGNAL(textEdited(QString)), this, SLOT(resetNotFound()));
×
129
        //connect(ui->lineEditQuery,         SIGNAL(editingFinished()),   this, SLOT(sendQuery()));
130
        connect(countdownTimer,              SIGNAL(timeout()),           this, SLOT(updateCountdown()));
×
131

132
        filterProxyModel = new QSortFilterProxyModel(this);
×
133
        filterProxyModel->setSourceModel(candidateObjectsModel);
×
134
        filterProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
×
135
        ui->listViewObjects->setModel(filterProxyModel);
×
136
        connect(ui->lineEditSearch, SIGNAL(textChanged(const QString&)),
×
137
                filterProxyModel, SLOT(setFilterFixedString(const QString&)));
×
138

139
        loadBookmarks();
×
140
        updateTexts();
×
141

142
        resetCountdown();
×
143
        resetDialog();
×
144
}
×
145

146
void MpcImportWindow::updateTexts()
×
147
{
148
        QString linkText("<a href=\"https://www.minorplanetcenter.net/iau/MPEph/MPEph.html\">Minor Planet &amp; Comet Ephemeris Service</a>");
×
149
        // TRANSLATORS: A link showing the text "Minor Planet & Comet Ephemeris Service" is inserted.
150
        QString queryString(q_("Query the MPC's %1:"));
×
151
        ui->labelQueryLink->setText(QString(queryString).arg(linkText));
×
152
        
153
        QString firstLine(q_("Only one result will be returned if the query is successful."));
×
154
        QString secondLine(q_("Both comets and asteroids can be identified with their number, name (in English) or IAU designation."));
×
155
        QString cPrefix("<b>C/</b>");
×
156
        QString pPrefix("<b>P/</b>");
×
157
        QString cometQuery("<tt>C/Halley</tt>");
×
158
        QString cometName("1P/Halley");
×
159
        QString asteroidQuery("<tt>Halley</tt>");
×
160
        QString asteroidName("(2688) Halley");
×
161
        QString nameWarning(q_("Comet <i>names</i> need to be prefixed with %1 or %2. If more than one comet matches a name, only the first result will be returned. For example, searching for \"%3\" will return %4, Halley's Comet, but a search for \"%5\" will return the asteroid %6."));
×
162
        QString thirdLine = QString(nameWarning).arg(cPrefix, pPrefix, cometQuery, cometName, asteroidQuery, asteroidName);
×
163
        ui->labelQueryInstructions->setText(QString("%1<br/>%2<br/>%3").arg(firstLine, secondLine, thirdLine));
×
164
}
×
165

166
void MpcImportWindow::resetDialog()
×
167
{
168
        ui->stackedWidget->setCurrentIndex(0);
×
169

170
        //ui->tabWidget->setCurrentIndex(0);
171
        ui->groupBoxType->setVisible(true);
×
172
        ui->radioButtonAsteroids->setChecked(true);
×
173

174
        ui->radioButtonURL->setChecked(true);
×
175
        ui->frameFile->setVisible(false);
×
176

177
        ui->lineEditFilePath->clear();
×
178
        ui->lineEditQuery->clear();
×
179
        ui->lineEditURL->setText("https://");
×
180
        ui->checkBoxAddBookmark->setChecked(false);
×
181
        ui->frameBookmarkTitle->setVisible(false);
×
182
        ui->comboBoxBookmarks->setCurrentIndex(0);
×
183

184
        ui->radioButtonUpdate->setChecked(true);
×
185
        ui->checkBoxOnlyOrbitalElements->setChecked(true);
×
186

187
        //TODO: Is this the right place?
188
        ui->pushButtonAbortQuery->setVisible(false);
×
189
        ui->pushButtonAbortDownload->setVisible(false);
×
190

191
        //Resetting the dialog should not reset the timer
192
        //resetCountdown();
193
        resetNotFound();
×
194
        enableInterface(true);
×
195
}
×
196

197
void MpcImportWindow::populateBookmarksList()
×
198
{
199
        ui->comboBoxBookmarks->clear();
×
200
        ui->comboBoxBookmarks->addItem(q_("Select bookmark..."));
×
201
        QStringList bookmarkTitles(bookmarks.value(importType).keys());
×
202
        bookmarkTitles.sort();
×
203
        ui->comboBoxBookmarks->addItems(bookmarkTitles);
×
204
}
×
205

206
void MpcImportWindow::retranslate()
×
207
{
208
        if (dialog)
×
209
        {
210
                ui->retranslateUi(dialog);
×
211
                updateTexts();
×
212
        }
213
}
×
214

215
void MpcImportWindow::acquireObjectData()
×
216
{
217
        if (ui->radioButtonFile->isChecked())
×
218
        {
219
                QString filePath = ui->lineEditFilePath->text();
×
220
                if (filePath.isEmpty())
×
221
                        return;
×
222

223
                QList<SsoElements> objects = readElementsFromFile(importType, filePath);
×
224
                if (objects.isEmpty())
×
225
                        return;
×
226

227
                //Temporary, until the slot/socket mechanism is ready
228
                populateCandidateObjects(objects);
×
229
                ui->stackedWidget->setCurrentIndex(1);
×
230
        }
×
231
        else if (ui->radioButtonURL->isChecked())
×
232
        {
233
                QString url = ui->lineEditURL->text();
×
234
                if (url.isEmpty())
×
235
                        return;
×
236
                startDownload(url);
×
237
        }
×
238
        //close();
239
}
240

241
void MpcImportWindow::addObjects()
×
242
{
243
        disconnect(ssoManager, SIGNAL(solarSystemChanged()), this, SLOT(resetDialog()));
×
244

245
        QList<QString> checkedObjectsNames;
×
246

247
        // Collect names of marked objects
248
        //TODO: Something smarter?
249
        for (int row = 0; row < candidateObjectsModel->rowCount(); row++)
×
250
        {
251
                QStandardItem * item = candidateObjectsModel->item(row);
×
252
                if (item->checkState() == Qt::Checked)
×
253
                {
254
                        checkedObjectsNames.append(item->text());
×
255
                        if (row==0)
×
256
                                SearchDialog::extSearchText = item->text();
×
257
                }
258
        }
259
        //qDebug() << "Checked:" << checkedObjectsNames;
260

261
        // collect from candidatesForAddition all candidates that were selected by the user into `approvedForAddition` ...
262
        QList<SsoElements> approvedForAddition;
×
263
        for (int i = 0; i < candidatesForAddition.count(); i++)
×
264
        {
265
                auto candidate = candidatesForAddition.at(i);
×
266
                QString name = candidate.value("name").toString();
×
267
                if (checkedObjectsNames.contains(name))
×
268
                        approvedForAddition.append(candidate);
×
269
        }
×
270

271
        //qDebug() << "Approved for addition:" << approvedForAddition;
272

273
        // collect all new (!!!) candidates that were selected by the user into `approvedForUpdate`
274
        // if the user opted to overwrite, those candidates are added to `approvedForAddition` instead
275
        bool overwrite = ui->radioButtonOverwrite->isChecked();
×
276
        QList<SsoElements> approvedForUpdate;
×
277
        for (int j = 0; j < candidatesForUpdate.count(); j++)
×
278
        {
279
                auto candidate = candidatesForUpdate.at(j);
×
280
                QString name = candidate.value("name").toString();
×
281
                if (checkedObjectsNames.contains(name))
×
282
                {
283
                        // XXX: odd... if "overwrite" is false, data is overwritten anyway.
284
                        if (overwrite)
×
285
                        {
286
                                approvedForAddition.append(candidate);
×
287
                        }
288
                        else
289
                        {
290
                                approvedForUpdate.append(candidate);
×
291
                        }
292
                }
293
        }
×
294

295
        //qDebug() << "Approved for updates:" << approvedForUpdate;
296

297
        // append *** + update *** the approvedForAddition candidates to custom solar system config
298
        ssoManager->appendToSolarSystemConfigurationFile(approvedForAddition);
×
299

300
        // if instead "update existing objects" was selected, update existing candidates from `approvedForUpdate` in custom solar system config
301
        // update name, MPC number, orbital elements
302
        // if the user asked more to update, include type (asteroid, comet, plutino, cubewano, ...) and magnitude parameters
303
        bool update = ui->radioButtonUpdate->isChecked();
×
304
        // ASSERT(update != overwrite); // because of radiobutton behaviour. TODO this UI is not very clear anyway.
305
        if (update) 
×
306
        {
307
                SolarSystemEditor::UpdateFlags flags(SolarSystemEditor::UpdateNameAndNumber | SolarSystemEditor::UpdateOrbitalElements);
×
308
                bool onlyorbital = ui->checkBoxOnlyOrbitalElements->isChecked();
×
309
                if (!onlyorbital)
×
310
                {
311
                        flags |= SolarSystemEditor::UpdateType;
×
312
                        flags |= SolarSystemEditor::UpdateMagnitudeParameters;
×
313
                }
314

315
                ssoManager->updateSolarSystemConfigurationFile(approvedForUpdate, flags);
×
316
        }
317

318
        //Refresh the Solar System
319
        GETSTELMODULE(SolarSystem)->reloadPlanets();
×
320

321
        resetDialog();
×
322
        emit objectsImported();
×
323
}
×
324

325
void MpcImportWindow::discardObjects()
×
326
{
327
        resetDialog();
×
328
}
×
329

330
void MpcImportWindow::pasteClipboardURL()
×
331
{
332
        ui->lineEditURL->setText(QGuiApplication::clipboard()->text());
×
333
}
×
334

335
void MpcImportWindow::selectFile()
×
336
{
337
        QString filter = q_("Plain Text File");
×
338
        filter.append(" (*.txt);;");
×
339
        filter.append(q_("All Files"));
×
340
        filter.append(" (*.*)");
×
341
        QString filePath = QFileDialog::getOpenFileName(&StelMainView::getInstance(), q_("Select a file"), QDir::homePath(), filter);
×
342
        ui->lineEditFilePath->setText(filePath);
×
343
}
×
344

345
void MpcImportWindow::bookmarkSelected(int bookmarkIndex)
×
346
{
347
        const QString bookmarkTitle=ui->comboBoxBookmarks->itemText(bookmarkIndex);
×
348
        if (bookmarkTitle.isEmpty() || bookmarks.value(importType).value(bookmarkTitle).isEmpty())
×
349
        {
350
                ui->lineEditURL->clear();
×
351
                return;
×
352
        }
353
        QString bookmarkUrl = bookmarks.value(importType).value(bookmarkTitle);
×
354
        ui->lineEditURL->setText(bookmarkUrl);
×
355
}
×
356

357
void MpcImportWindow::populateCandidateObjects(QList<SsoElements> objects)
×
358
{
359
        candidatesForAddition.clear();        // new objects
×
360
        candidatesForUpdate.clear();        // existing objects
×
361

362
        //Get a list of the current objects
363
        //QHash<QString,QString> defaultSsoIdentifiers = ssoManager->getDefaultSsoIdentifiers();
364
        QHash<QString,QString> loadedSsoIdentifiers = ssoManager->listAllLoadedSsoIdentifiers();
×
365

366
        //Separate the objects into visual (internally unsorted, anyone?) groups in the list
367

368
        //int newDefaultSsoIndex = 0;
369
        int newLoadedSsoIndex = 0; // existing objects
×
370
        int newNovelSsoIndex = 0; // new objects
×
371

372
        int insertionIndex = 0; // index of object to be inserted next
×
373

374
        QStandardItemModel * model = candidateObjectsModel;
×
375
        model->clear();
×
376
        model->setColumnCount(1);
×
377

378
        for (auto object : objects)
×
379
        {
380
                QString name = object.value("name").toString();
×
381
                if (name.isEmpty())
×
382
                        continue;
×
383

384
                QString group = object.value("section_name").toString();
×
385
                if (group.isEmpty())
×
386
                        continue;
×
387

388
                //Prevent name conflicts between asteroids and moons
389
                if (loadedSsoIdentifiers.contains(name))
×
390
                {
391
                        if (loadedSsoIdentifiers.value(name) != group)
×
392
                        {
393
                                name.append('*');
×
394
                                object.insert("name", name);
×
395
                        }
396
                }
397

398
                QStandardItem * item = new QStandardItem();
×
399
                item->setText(name);
×
400
                item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
×
401
                item->setCheckState(Qt::Unchecked);
×
402

403
//                if (defaultSsoIdentifiers.contains(name))
404
//                {
405
//                        //Duplicate of a default solar system object
406
//                        QFont itemFont(item->font());
407
//                        itemFont.setBold(true);
408
//                        item->setFont(itemFont);
409

410
//                        candidatesForUpdate.append(object);
411

412
//                        insertionIndex = newDefaultSsoIndex;
413
//                        newDefaultSsoIndex++;
414
//                        newLoadedSsoIndex++;
415
//                        newNovelSsoIndex++;
416
//                }
417
//                else
418

419
                // identify existing (in italic) and new objects
420
                if (loadedSsoIdentifiers.contains(name))
×
421
                {
422
                        //Duplicate of another existing object
423
                        QFont itemFont(item->font());
×
424
                        itemFont.setItalic(true);
×
425
                        item->setFont(itemFont);
×
426

427
                        candidatesForUpdate.append(object);
×
428

429
                        insertionIndex = newLoadedSsoIndex;
×
430
                        newLoadedSsoIndex++;
×
431
                        newNovelSsoIndex++;
×
432
                }
×
433
                else
434
                {
435
                        candidatesForAddition.append(object);
×
436

437
                        insertionIndex = newNovelSsoIndex;
×
438
                        newNovelSsoIndex++;
×
439
                }
440

441
                model->insertRow(insertionIndex, item);
×
442
        }
×
443

444
        //Scroll to the first items
445
        ui->listViewObjects->scrollToTop();
×
446
}
×
447

448
void MpcImportWindow::enableInterface(bool enable)
×
449
{
450
        ui->groupBoxType->setVisible(enable);
×
451

452
        ui->frameFile->setEnabled(enable);
×
453
        ui->frameURL->setEnabled(enable);
×
454

455
        ui->radioButtonFile->setEnabled(enable);
×
456
        ui->radioButtonURL->setEnabled(enable);
×
457

458
        ui->pushButtonAcquire->setEnabled(enable);
×
459
}
×
460

461
SsoElements MpcImportWindow::readElementsFromString(QString elements)
×
462
{
463
        Q_ASSERT(ssoManager);
×
464

465
        switch (importType)
×
466
        {
467
                case MpcComets:
×
468
                        return ssoManager->readMpcOneLineCometElements(elements);
×
469
                case MpcMinorPlanets:
×
470
                default:
471
                        return ssoManager->readMpcOneLineMinorPlanetElements(elements);
×
472
        }
473
}
474

475
QList<SsoElements> MpcImportWindow::readElementsFromFile(ImportType type, QString filePath)
×
476
{
477
        Q_ASSERT(ssoManager);
×
478

479
        switch (type)
×
480
        {
481
                case MpcComets:
×
482
                        return ssoManager->readMpcOneLineCometElementsFromFile(filePath);
×
483
                case MpcMinorPlanets:
×
484
                default:
485
                        return ssoManager->readMpcOneLineMinorPlanetElementsFromFile(filePath);
×
486
        }
487
}
488

489
void MpcImportWindow::switchImportType(bool)
×
490
{
491
        if (ui->radioButtonAsteroids->isChecked())
×
492
        {
493
                importType = MpcMinorPlanets;
×
494
        }
495
        else
496
        {
497
                importType = MpcComets;
×
498
        }
499

500
        populateBookmarksList();
×
501

502
        //Clear the fields
503
        //ui->lineEditSingle->clear();
504
        ui->lineEditFilePath->clear();
×
505
        ui->lineEditURL->clear();
×
506

507
        //If one of the options is selected, show the rest of the dialog
508
        ui->groupBoxSource->setVisible(true);
×
509
}
×
510

511
void MpcImportWindow::setCheckState(Qt::CheckState state)
×
512
{
513
        int rowCount = filterProxyModel->rowCount();
×
514
        if (rowCount < 1)
×
515
                return;
×
516

517
        for (int row = 0; row < rowCount; row++)
×
518
        {
519
                QModelIndex proxyIndex = filterProxyModel->index(row, 0);
×
520
                QModelIndex index = filterProxyModel->mapToSource(proxyIndex);
×
521
                QStandardItem * item = candidateObjectsModel->itemFromIndex(index);
×
522
                if (item)
×
523
                        item->setCheckState(state);
×
524
        }
525
}
526

527
void MpcImportWindow::markAll()
×
528
{
529
        setCheckState(Qt::Checked);
×
530
}
×
531

532
void MpcImportWindow::unmarkAll()
×
533
{
534
        setCheckState(Qt::Unchecked);
×
535
}
×
536

537
void MpcImportWindow::updateDownloadProgress(qint64 bytesReceived, qint64 bytesTotal)
×
538
{
539
        if (downloadProgressBar == nullptr)
×
540
                return;
×
541

542
        int currentValue = 0;
×
543
        int endValue = 0;
×
544

545
        if (bytesTotal > -1 && bytesReceived <= bytesTotal)
×
546
        {
547
                //Round to the greatest possible derived unit
548
                while (bytesTotal > 1024)
×
549
                {
550
                        bytesReceived >>= 10;
×
551
                        bytesTotal    >>= 10;
×
552
                }
553
                currentValue = static_cast<int>(bytesReceived);
×
554
                endValue = static_cast<int>(bytesTotal);
×
555
        }
556

557
        downloadProgressBar->setValue(currentValue);
×
558
        downloadProgressBar->setRange(0, endValue);
×
559
}
560

561
void MpcImportWindow::updateQueryProgress(qint64, qint64)
×
562
{
563
        if (queryProgressBar == nullptr)
×
564
                return;
×
565

566
        //Just show activity
567
        queryProgressBar->setValue(0);
×
568
        queryProgressBar->setRange(0, 0);
×
569
}
570

571
void MpcImportWindow::startDownload(QString urlString)
×
572
{
573
        if (downloadReply)
×
574
        {
575
                //There's already an operation in progress?
576
                //TODO
577
                return;
×
578
        }
579

580
        QUrl url(urlString);
×
581
        if (!url.isValid())
×
582
        {
583
                qWarning() << "Invalid URL:" << urlString;
×
584
                return;
×
585
        }
586
        //qDebug() << url.toString();
587

588
        //TODO: Interface changes!
589

590
        downloadProgressBar = StelApp::getInstance().addProgressBar();
×
591
        downloadProgressBar->setValue(0);
×
592
        downloadProgressBar->setRange(0, 0);
×
593

594
        //TODO: Better handling of the interface
595
        //dialog->setVisible(false);
596
        enableInterface(false);
×
597
        ui->pushButtonAbortDownload->setVisible(true);
×
598

599
        connect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(downloadComplete(QNetworkReply*)));
×
600
        QNetworkRequest request;
×
601
        request.setUrl(QUrl(url));
×
602
        request.setRawHeader("User-Agent", StelUtils::getUserAgentString().toUtf8());
×
603
#if (QT_VERSION<QT_VERSION_CHECK(6,0,0))
604
        request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, true);
×
605
#endif
606
        downloadReply = networkManager->get(request);
×
607
        connect(downloadReply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(updateDownloadProgress(qint64,qint64)));
×
608
}
×
609

610
void MpcImportWindow::abortDownload()
×
611
{
612
        if (downloadReply == nullptr || downloadReply->isFinished())
×
613
                return;
×
614

615
        qDebug() << "Aborting download...";
×
616

617
        disconnect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(downloadComplete(QNetworkReply*)));
×
618
        deleteDownloadProgressBar();
×
619

620
        downloadReply->abort();
×
621
        downloadReply->deleteLater();
×
622
        downloadReply = nullptr;
×
623

624
        enableInterface(true);
×
625
        ui->pushButtonAbortDownload->setVisible(false);
×
626
}
627

628
void MpcImportWindow::downloadComplete(QNetworkReply *reply)
×
629
{
630
        disconnect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(downloadComplete(QNetworkReply*)));
×
631
        deleteDownloadProgressBar();
×
632
        ui->pushButtonAbortDownload->setVisible(false);
×
633

634
        /*
635
        qDebug() << "reply->isOpen():" << reply->isOpen()
636
                << "reply->isReadable():" << reply->isReadable()
637
                << "reply->isFinished():" << reply->isFinished();
638
        */
639

640
        if(reply->error() || reply->bytesAvailable()==0)
×
641
        {
642
                qWarning() << "Download error: While downloading"
×
643
                           << reply->url().toString()
×
644
                                   << "the following error occurred:"
×
645
                                   << reply->errorString();
×
646
                enableInterface(true);
×
647
                reply->deleteLater();
×
648
                downloadReply = nullptr;
×
649
                return;
×
650
        }
651

652
        QList<SsoElements> objects;
×
653
        QTemporaryFile file;
×
654
        if (file.open())
×
655
        {
656
                file.write(reply->readAll());
×
657
                file.close();
×
658
                objects = readElementsFromFile(importType, file.fileName());
×
659
        }
660
        else
661
        {
662
                qWarning() << "Unable to open a temporary file. Aborting operation.";
×
663
        }
664

665
        if (objects.isEmpty())
×
666
        {
667
                qWarning() << "No objects found in the file downloaded from"
×
668
                           << reply->url().toString();
×
669
        }
670
        else
671
        {
672
                //The request has been successful: add the URL to bookmarks?
673
                if (ui->checkBoxAddBookmark->isChecked())
×
674
                {
675
                        QString url = reply->url().toString();
×
676
                        QString title = ui->lineEditBookmarkTitle->text().trimmed();
×
677
                        //If no title has been entered, use the URL as a title
678
                        if (title.isEmpty())
×
679
                                title = url;
×
680
                        if (!bookmarks.value(importType).values().contains(url))
×
681
                        {
682
                                bookmarks[importType].insert(title, url);
×
683
                                populateBookmarksList();
×
684
                                saveBookmarks();
×
685
                        }
686
                }
×
687
        }
688

689
        reply->deleteLater();
×
690
        downloadReply = nullptr;
×
691

692
        //Temporary, until the slot/socket mechanism is ready
693
        populateCandidateObjects(objects);
×
694
        ui->stackedWidget->setCurrentIndex(1);
×
695
        //As this window is persistent, if the Solar System is changed
696
        //while there is a list, it should be reset.
697
        connect(ssoManager, SIGNAL(solarSystemChanged()), this, SLOT(resetDialog()));
×
698
}
×
699

700
void MpcImportWindow::deleteDownloadProgressBar()
×
701
{
702
        disconnect(this, SLOT(updateDownloadProgress(qint64,qint64)));
×
703

704
        if (downloadProgressBar)
×
705
        {
706
                StelApp::getInstance().removeProgressBar(downloadProgressBar);
×
707
                downloadProgressBar = nullptr;
×
708
        }
709
}
×
710

711
void MpcImportWindow::sendQuery()
×
712
{
713
        if (queryReply != nullptr)
×
714
                return;
×
715

716
        query = ui->lineEditQuery->text().trimmed();
×
717
        if (query.isEmpty())
×
718
                return;
×
719

720
        //Progress bar
721
        queryProgressBar = StelApp::getInstance().addProgressBar();
×
722
        queryProgressBar->setValue(0);
×
723
        queryProgressBar->setRange(0, 0);
×
724
        queryProgressBar->setFormat(q_("Searching..."));
×
725

726
        //TODO: Better handling of the interface
727
        enableInterface(false);
×
728
        ui->labelQueryMessage->setVisible(false);
×
729

730
        startCountdown();
×
731
        ui->pushButtonAbortQuery->setVisible(true);
×
732

733
        //sendQueryToUrl(QUrl("http://stellarium.org/mpc-mpeph"));
734
        //sendQueryToUrl(QUrl("http://scully.cfa.harvard.edu/cgi-bin/mpeph2.cgi"));
735
        // MPC requirements now :(
736
        sendQueryToUrl(QUrl("https://www.minorplanetcenter.net/cgi-bin/mpeph2.cgi"));
×
737
}
738

739
void MpcImportWindow::sendQueryToUrl(QUrl url)
×
740
{
741
        QUrlQuery q(url);
×
742
        q.addQueryItem("ty","e");//Type: ephemerides
×
743
        q.addQueryItem("TextArea", query);//Object name query
×
744
        q.addQueryItem("e", "-1");//Elements format: MPC 1-line
×
745
        //Switch to MPC 1-line format --AW
746
        //XEphem's format is used instead because it doesn't truncate object names.
747
        //q.addQueryItem("e", "3");//Elements format: XEphem
748
        //Yes, all of the rest are necessary
749
        q.addQueryItem("d","");
×
750
        q.addQueryItem("l","");
×
751
        q.addQueryItem("i","");
×
752
        q.addQueryItem("u","d");
×
753
        q.addQueryItem("uto", "0");
×
754
        q.addQueryItem("c", "");
×
755
        q.addQueryItem("long", "");
×
756
        q.addQueryItem("lat", "");
×
757
        q.addQueryItem("alt", "");
×
758
        q.addQueryItem("raty", "a");
×
759
        q.addQueryItem("s", "t");
×
760
        q.addQueryItem("m", "m");
×
761
        q.addQueryItem("adir", "S");
×
762
        q.addQueryItem("oed", "");
×
763
        q.addQueryItem("resoc", "");
×
764
        q.addQueryItem("tit", "");
×
765
        q.addQueryItem("bu", "");
×
766
        q.addQueryItem("ch", "c");
×
767
        q.addQueryItem("ce", "f");
×
768
        q.addQueryItem("js", "f");
×
769
        url.setQuery(q);
×
770

771
        QNetworkRequest request;
×
772
        request.setUrl(QUrl(url));
×
773
        request.setRawHeader("User-Agent", StelUtils::getUserAgentString().toUtf8());
×
774
        request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); //Is this really necessary?
×
775
        request.setHeader(QNetworkRequest::ContentLengthHeader, url.query(QUrl::FullyEncoded).length());
×
776
#if (QT_VERSION<QT_VERSION_CHECK(6,0,0))
777
        request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, true);
×
778
#endif
779

780
        connect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(receiveQueryReply(QNetworkReply*)));
×
781
        queryReply = networkManager->post(request, url.query(QUrl::FullyEncoded).toUtf8());        
×
782
        connect(queryReply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(updateQueryProgress(qint64,qint64)));
×
783
}
×
784

785
void MpcImportWindow::abortQuery()
×
786
{
787
        if (queryReply == nullptr)
×
788
                return;
×
789

790
        disconnect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(receiveQueryReply(QNetworkReply*)));
×
791
        deleteQueryProgressBar();
×
792

793
        queryReply->abort();
×
794
        queryReply->deleteLater();
×
795
        queryReply = nullptr;
×
796

797
        //resetCountdown();
798
        enableInterface(true);
×
799
        ui->pushButtonAbortQuery->setVisible(false);
×
800
}
801

802
void MpcImportWindow::receiveQueryReply(QNetworkReply *reply)
×
803
{
804
        if (reply == nullptr)
×
805
                return;
×
806

807
        disconnect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(receiveQueryReply(QNetworkReply*)));
×
808

809
        int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
×
810
        if (statusCode == 301 || statusCode == 302 || statusCode == 307)
×
811
        {
812
                QUrl rawUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
×
813
                QUrl redirectUrl(rawUrl.toString(QUrl::RemoveQuery));
×
814
                qDebug() << "The search query has been redirected to" << redirectUrl.toString();
×
815

816
                //TODO: Add counter and cycle check.
817

818
                reply->deleteLater();
×
819
                queryReply = nullptr;
×
820
                sendQueryToUrl(redirectUrl);
×
821
                return;
×
822
        }
×
823

824
        deleteQueryProgressBar();
×
825

826
        //Hide the abort button - a reply has been received
827
        ui->pushButtonAbortQuery->setVisible(false);
×
828

829
        if (reply->error() || reply->bytesAvailable()==0)
×
830
        {
831
                qWarning() << "Download error: While trying to access"
×
832
                           << reply->url().toString()
×
833
                           << "the following error occurred:"
×
834
                           << reply->errorString();
×
835
                ui->labelQueryMessage->setText(reply->errorString());//TODO: Decide if this is a good idea
×
836
                ui->labelQueryMessage->setVisible(true);
×
837
                enableInterface(true);
×
838

839
                reply->deleteLater();
×
840
                queryReply = nullptr;
×
841
                return;
×
842
        }
843

844
        QString contentType = reply->header(QNetworkRequest::ContentTypeHeader).toString();
×
845
        QString contentDisposition = reply->rawHeader(QByteArray("Content-disposition"));
×
846
        if (contentType == "text/ascii" &&
×
847
            contentDisposition == "attachment; filename=elements.txt")
×
848
        {
849
                readQueryReply(reply);
×
850
        }
851
        else
852
        {
853
                ui->labelQueryMessage->setText("Object not found.");
×
854
                ui->labelQueryMessage->setVisible(true);
×
855
                enableInterface(true);
×
856
        }
857

858
        reply->deleteLater();
×
859
        queryReply = nullptr;
×
860
}
×
861

862
void MpcImportWindow::readQueryReply(QNetworkReply * reply)
×
863
{
864
        Q_ASSERT(reply);
×
865

866
        QList<SsoElements> objects;
×
867
        QTemporaryFile file;
×
868
        if (file.open())
×
869
        {
870
                file.write(reply->readAll());                
×
871
                file.close();
×
872

873
                static const QRegularExpression cometIAUDesignation("[PCDXI]/");
×
874
                static const QRegularExpression cometDesignation("(\\d)+[PCDXI]/");
×
875
                QString queryData = ui->lineEditQuery->text().trimmed();
×
876

877
                if (queryData.indexOf(cometDesignation) == 0 || queryData.indexOf(cometIAUDesignation) == 0)
×
878
                        objects = readElementsFromFile(MpcComets, file.fileName());
×
879
                else
880
                        objects = readElementsFromFile(MpcMinorPlanets, file.fileName());
×
881

882
                /*
883
                //Try to read it as a comet first?
884
                objects = readElementsFromFile(MpcComets, file.fileName());
885
                if (objects.isEmpty())
886
                        objects = readElementsFromFile(MpcMinorPlanets, file.fileName());
887
                */
888
                //XEphem given wrong data for comets --AW
889
                //objects = ssoManager->readXEphemOneLineElementsFromFile(file.fileName());
890
        }
×
891
        else
892
        {
893
                qWarning() << "Unable to open a temporary file. Aborting operation.";
×
894
        }
895

896
        if (objects.isEmpty())
×
897
        {
898
                qWarning() << "No objects found in the file downloaded from"
×
899
                                   << reply->url().toString();
×
900
        }
901
        else
902
        {
903
                //The request has been successful: add the URL to bookmarks?
904
                if (ui->checkBoxAddBookmark->isChecked())
×
905
                {
906
                        QString url = reply->url().toString();
×
907
                        if (!bookmarks.value(importType).values().contains(url))
×
908
                        {
909
                                //Use the URL as a title for now
910
                                bookmarks[importType].insert(url, url);
×
911
                        }
912
                }
×
913

914
                //Temporary, until the slot/socket mechanism is ready
915
                populateCandidateObjects(objects);
×
916
                ui->stackedWidget->setCurrentIndex(1);
×
917
        }
918
}
×
919

920
void MpcImportWindow::deleteQueryProgressBar()
×
921
{
922
        disconnect(this, SLOT(updateQueryProgress(qint64,qint64)));
×
923
        if (queryProgressBar)
×
924
        {
925
                StelApp::getInstance().removeProgressBar(queryProgressBar);
×
926
                queryProgressBar = nullptr;
×
927
        }
928
}
×
929

930
void MpcImportWindow::startCountdown()
×
931
{
932
        if (!countdownTimer->isActive())
×
933
                countdownTimer->start(1000);//1 second
×
934

935
        //Disable the interface
936
        ui->lineEditQuery->setEnabled(false);
×
937
        ui->pushButtonSendQuery->setEnabled(false);
×
938
}
×
939

940
void MpcImportWindow::resetCountdown()
×
941
{
942
        //Stop the timer
943
        if (countdownTimer->isActive())
×
944
        {
945
                countdownTimer->stop();
×
946

947
                //If the query is still active, kill it
948
                if (queryReply != nullptr && queryReply->isRunning())
×
949
                {
950
                        abortQuery();
×
951
                        ui->labelQueryMessage->setText("The query timed out. You can try again, now or later.");
×
952
                        ui->labelQueryMessage->setVisible(true);
×
953
                }
954
        }
955

956
        //Reset the counter
957
        countdown = 60;
×
958

959
        //Enable the interface
960
        ui->lineEditQuery->setEnabled(true);
×
961
        ui->pushButtonSendQuery->setEnabled(true);
×
962
}
×
963

964
void MpcImportWindow::updateCountdown()
×
965
{
966
        --countdown;
×
967
        if (countdown < 0)
×
968
        {
969
                resetCountdown();
×
970
        }
971
        //If there has been an answer
972
        else if (countdown > 50 && queryReply == nullptr)
×
973
        {
974
                resetCountdown();
×
975
        }
976
}
×
977

978
void MpcImportWindow::resetNotFound()
×
979
{
980
        ui->labelQueryMessage->setVisible(false);
×
981
}
×
982

983
void MpcImportWindow::loadBookmarks()
×
984
{
985
        bookmarks[MpcComets].clear();
×
986
        bookmarks[MpcMinorPlanets].clear();
×
987

988
        QString bookmarksFilePath(StelFileMgr::getUserDir() + "/modules/SolarSystemEditor/bookmarks.json");
×
989
        bool outdated = false;
×
990
        if (StelFileMgr::isReadable(bookmarksFilePath))
×
991
        {
992
                QFile bookmarksFile(bookmarksFilePath);
×
993
                if (bookmarksFile.open(QFile::ReadOnly | QFile::Text))
×
994
                {
995
                        QVariantMap jsonRoot;
×
996
                        QString fileVersion = "0.0.0";
×
997
                        try
998
                        {
999
                                jsonRoot = StelJsonParser::parse(bookmarksFile.readAll()).toMap();
×
1000
                                bookmarksFile.close();
×
1001

1002
                                fileVersion = jsonRoot.value("version").toString();
×
1003
                                if (fileVersion.isEmpty())
×
1004
                                        fileVersion = "0.0.0";
×
1005

1006
                                loadBookmarksGroup(jsonRoot.value("mpcMinorPlanets").toMap(), bookmarks[MpcMinorPlanets]);
×
1007
                                loadBookmarksGroup(jsonRoot.value("mpcComets").toMap(), bookmarks[MpcComets]);
×
1008
                        }
1009
                        catch (std::runtime_error &e)
×
1010
                        {
1011
                                qDebug() << "File format is wrong! Error: " << e.what();
×
1012
                                outdated = true;
×
1013
                        }
×
1014

1015
                        if (StelUtils::compareVersions(fileVersion, SOLARSYSTEMEDITOR_PLUGIN_VERSION)<0)
×
1016
                                outdated = true; // Oops... the list is outdated!
×
1017

1018
                        //If nothing was read, continue
1019
                        if (!bookmarks.value(MpcComets).isEmpty() && !bookmarks[MpcMinorPlanets].isEmpty() && !outdated)
×
1020
                                return;
×
1021
                }
×
1022
        }
×
1023

1024
        if (outdated)
×
1025
                qDebug() << "Bookmarks file is outdated! The list will be upgraded by hard-coded bookmarks.";
×
1026
        else
1027
                qDebug() << "Bookmarks file can't be read. Hard-coded bookmarks will be used.";
×
1028

1029
        // Remove outdated bookmarks for minor planets
1030
        QHashIterator<QString, QString> it(bookmarks[MpcMinorPlanets]);
×
1031
        while (it.hasNext())
×
1032
        {
1033
                it.next();
×
1034
                if (it.value().contains("dss.stellarium.org") || it.value().contains("2018/Soft00Bright.txt"))
×
1035
                        bookmarks[MpcMinorPlanets].remove(it.key());
×
1036
        }
1037

1038
        //Initialize with hard-coded values
1039
        // NOTE: this list is reordered anyway when loaded
1040

1041
        bookmarks[MpcMinorPlanets].insert("MPC's list of observable critical-list numbered minor planets",         "https://www.minorplanetcenter.net/iau/Ephemerides/CritList/Soft00CritList.txt");
×
1042
        bookmarks[MpcMinorPlanets].insert("MPC's list of observable distant minor planets",                         "https://www.minorplanetcenter.net/iau/Ephemerides/Distant/Soft00Distant.txt");
×
1043
        bookmarks[MpcMinorPlanets].insert("MPC's list of observable unusual minor planets",                         "https://www.minorplanetcenter.net/iau/Ephemerides/Unusual/Soft00Unusual.txt");
×
1044
        bookmarks[MpcMinorPlanets].insert("MPC's list of bright minor planets for 2023",                        "https://www.minorplanetcenter.net/iau/Ephemerides/Bright/2023/Soft00Bright.txt");
×
1045

1046
        bookmarks[MpcMinorPlanets].insert("MPCORB: near-Earth asteroids (NEAs)",                                 "https://www.minorplanetcenter.net/iau/MPCORB/NEA.txt");
×
1047
        bookmarks[MpcMinorPlanets].insert("MPCORB: potentially hazardous asteroids (PHAs)",                         "https://www.minorplanetcenter.net/iau/MPCORB/PHA.txt");
×
1048
        bookmarks[MpcMinorPlanets].insert("MPCORB: TNOs, Centaurs and SDOs",                                         "https://www.minorplanetcenter.net/iau/MPCORB/Distant.txt");
×
1049
        bookmarks[MpcMinorPlanets].insert("MPCORB: other unusual objects",                                         "https://www.minorplanetcenter.net/iau/MPCORB/Unusual.txt");
×
1050
        bookmarks[MpcMinorPlanets].insert("MPCORB: elements of NEAs for current epochs (today)",                 "https://www.minorplanetcenter.net/iau/MPCORB/NEAm00.txt");
×
1051
        bookmarks[MpcMinorPlanets].insert("MPCORB: orbits from the latest DOU MPEC",                                 "https://www.minorplanetcenter.net/iau/MPCORB/DAILY.DAT");
×
1052

1053
        bookmarks[MpcMinorPlanets].insert("MPCAT: Unusual minor planets (including NEOs)",                         "https://www.minorplanetcenter.net/iau/ECS/MPCAT/unusual.txt");
×
1054
        bookmarks[MpcMinorPlanets].insert("MPCAT: Distant minor planets (Centaurs and transneptunians)",         "https://www.minorplanetcenter.net/iau/ECS/MPCAT/distant.txt");
×
1055

1056
        const int start = 0;
×
1057
        const int finish = 61;
×
1058
        const int nsize = 6;
×
1059
        const QChar dash = QChar(0x2014);
×
1060

1061
        QString limits, idx, leftLimit, rightLimit;
×
1062

1063
        for (int i=start; i<=finish; i++)
×
1064
        {
1065
                leftLimit = (i==start) ? QString::number(1).rightJustified(nsize) : QString::number(i*10000).rightJustified(nsize);
×
1066
                rightLimit = (i==finish) ? "..." : QString::number(i*10000 + 9999).rightJustified(nsize);
×
1067
                limits = QString("%1%2%3").arg(leftLimit, dash, rightLimit);
×
1068
                idx = QString::number(i+1).rightJustified(2, '0');
×
1069
                bookmarks[MpcMinorPlanets].insert(
×
1070
                        QString("MPCAT: Numbered objects (%1)").arg(limits), 
×
1071
                        QString("http://dss.stellarium.org/MPC/mpn-%1.txt").arg(idx)
×
1072
                        );
1073
        }
1074

1075
        bookmarks[MpcComets].insert("MPC's list of observable comets",        "https://www.minorplanetcenter.net/iau/Ephemerides/Comets/Soft00Cmt.txt");
×
1076
        bookmarks[MpcComets].insert("MPCORB: comets",                        "https://www.minorplanetcenter.net/iau/MPCORB/CometEls.txt");
×
1077
        bookmarks[MpcComets].insert("MPCORB: all comets and A/-objects","https://www.minorplanetcenter.net/iau/MPCORB/AllCometEls.txt");
×
1078

1079
        bookmarks[MpcComets].insert("Gideon van Buitenen: comets",        "http://astro.vanbuitenen.nl/cometelements?format=mpc&mag=obs");
×
1080

1081
        //Try to save them to a file
1082
        saveBookmarks();
×
1083
}
×
1084

1085
void MpcImportWindow::loadBookmarksGroup(QVariantMap source, Bookmarks & bookmarkGroup)
×
1086
{
1087
        if (source.isEmpty())
×
1088
                return;
×
1089

1090
        QMapIterator<QString, QVariant> it(source);
×
1091
        while (it.hasNext())
×
1092
        {
1093
                it.next();
×
1094
                QString url = it.value().toString();
×
1095
                if (!url.isEmpty())
×
1096
                        bookmarkGroup.insert(it.key(), url);
×
1097
        }
×
1098
}
×
1099

1100
void MpcImportWindow::saveBookmarks()
×
1101
{
1102
        try
1103
        {
1104
                StelFileMgr::makeSureDirExistsAndIsWritable(StelFileMgr::getUserDir() + "/modules/SolarSystemEditor");
×
1105

1106
                QVariantMap jsonRoot;
×
1107

1108
                QString bookmarksFilePath(StelFileMgr::getUserDir() + "/modules/SolarSystemEditor/bookmarks.json");
×
1109

1110
                //If the file exists, load it first
1111
                if (StelFileMgr::isReadable(bookmarksFilePath))
×
1112
                {
1113
                        QFile bookmarksFile(bookmarksFilePath);
×
1114
                        if (bookmarksFile.open(QFile::ReadOnly | QFile::Text))
×
1115
                        {
1116
                                jsonRoot = StelJsonParser::parse(bookmarksFile.readAll()).toMap();
×
1117
                                bookmarksFile.close();
×
1118
                        }
1119
                }
×
1120

1121
                QFile bookmarksFile(bookmarksFilePath);
×
1122
                if (bookmarksFile.open(QFile::WriteOnly | QFile::Truncate | QFile::Text))
×
1123
                {
1124
                        jsonRoot.insert("version", SOLARSYSTEMEDITOR_PLUGIN_VERSION);
×
1125

1126
                        QVariantMap minorPlanetsObject;
×
1127
                        saveBookmarksGroup(bookmarks[MpcMinorPlanets], minorPlanetsObject);
×
1128
                        //qDebug() << minorPlanetsObject.keys();
1129
                        jsonRoot.insert("mpcMinorPlanets", minorPlanetsObject);
×
1130

1131
                        QVariantMap cometsObject;
×
1132
                        saveBookmarksGroup(bookmarks[MpcComets], cometsObject);
×
1133
                        jsonRoot.insert("mpcComets", cometsObject);
×
1134

1135
                        StelJsonParser::write(jsonRoot, &bookmarksFile);
×
1136
                        bookmarksFile.close();
×
1137

1138
                        qDebug() << "Bookmarks file saved to" << QDir::toNativeSeparators(bookmarksFilePath);
×
1139
                        return;
×
1140
                }
×
1141
                else
1142
                {
1143
                        qDebug() << "Unable to write bookmarks file to" << QDir::toNativeSeparators(bookmarksFilePath);
×
1144
                }
1145
        }
×
1146
        catch (std::exception & e)
×
1147
        {
1148
                qDebug() << "Unable to save bookmarks file:" << e.what();
×
1149
        }
×
1150
}
1151

1152
void MpcImportWindow::saveBookmarksGroup(Bookmarks & bookmarkGroup, QVariantMap & output)
×
1153
{
1154
        QHashIterator<QString, QString>it(bookmarkGroup);
×
1155
        while (it.hasNext())
×
1156
        {
1157
                it.next();
×
1158
                output.insert(it.key(), it.value());
×
1159
        }
1160
}
×
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