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

Stellarium / stellarium / 15291801018

28 May 2025 04:52AM UTC coverage: 11.931% (-0.02%) from 11.951%
15291801018

push

github

alex-w
Added new set of navigational stars (XIX century)

0 of 6 new or added lines in 2 files covered. (0.0%)

14124 existing lines in 74 files now uncovered.

14635 of 122664 relevant lines covered (11.93%)

18291.42 hits per line

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

0.0
/src/gui/ObsListDialog.cpp
1
/*
2
 * Stellarium
3
 * Copyright (C) 2020 Jocelyn GIROD
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License along
16
 * with this program; if not, write to the Free Software Foundation, Inc.,
17
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
 */
19

20
#include <QDir>
21
#include <QFileDialog>
22
#include <QMessageBox>
23
#include <QUuid>
24

25
#include "StelTranslator.hpp"
26
#include "StelApp.hpp"
27
#include "StelMainView.hpp"
28
#include "StelObjectMgr.hpp"
29
#include "StelModuleMgr.hpp"
30
#include "StelLocationMgr.hpp"
31
#include "LandscapeMgr.hpp"
32
#include "StelFileMgr.hpp"
33
#include "StelPropertyMgr.hpp"
34
#include "StelMovementMgr.hpp"
35
#include "CustomObjectMgr.hpp"
36
#include "LandscapeMgr.hpp"
37
#include "HighlightMgr.hpp"
38
#include "StarMgr.hpp"
39
#include "NebulaMgr.hpp"
40
#include "StelCore.hpp"
41
#include "StelFileMgr.hpp"
42
#include "StelJsonParser.hpp"
43
#include "StelUtils.hpp"
44
#include "ObsListDialog.hpp"
45
#include "LabelMgr.hpp"
46

47
#include "ui_obsListDialog.h"
48

UNCOV
49
ObsListDialog::ObsListDialog(QObject *parent) :
×
50
        StelDialog("ObservingList", parent),
UNCOV
51
        ui(new Ui_obsListDialogForm()),
×
52
        core(StelApp::getInstance().getCore()),
×
53
        objectMgr(GETSTELMODULE(StelObjectMgr)),
×
54
        labelMgr(GETSTELMODULE(LabelMgr)),
×
55
        itemModel(new QStandardItemModel(0, ColumnCount)),
×
56
        observingListJsonPath(StelFileMgr::findFile("data", static_cast<StelFileMgr::Flags>(StelFileMgr::Directory | StelFileMgr::Writable)) + "/" + JSON_FILE_NAME),
×
57
        bookmarksJsonPath(    StelFileMgr::findFile("data", static_cast<StelFileMgr::Flags>(StelFileMgr::Directory | StelFileMgr::Writable)) + "/" + JSON_BOOKMARKS_FILE_NAME),
×
58
        tainted(false),
×
59
        isEditMode(false),
×
60
        isCreationMode(false)
×
61
{
62
        setObjectName("ObsListDialog");
×
UNCOV
63
        StelApp::getInstance().getStelPropertyManager()->registerObject(this);
×
64
        //Initialize the list of observing lists
65
        setObservingListHeaderNames();
×
66

67
        QSettings* conf  = StelApp::getInstance().getSettings();
×
UNCOV
68
        flagUseJD        = conf->value("bookmarks/useJD", false).toBool();
×
69
        flagUseLandscape = conf->value("bookmarks/useLandscape", false).toBool();
×
70
        flagUseLocation  = conf->value("bookmarks/useLocation", false).toBool();
×
71
        flagUseFov       = conf->value("bookmarks/useFOV", false).toBool();
×
72
}
×
73

74
ObsListDialog::~ObsListDialog() {
×
75
        // Only on exit we may need to write
76
        if (tainted)
×
77
        {
78
                // At this point we have added our lists to the observingLists map. Now update the jsonMap and store to file.
UNCOV
79
                QFile jsonFile(observingListJsonPath);
×
UNCOV
80
                if (!jsonFile.open(QIODevice::ReadWrite | QIODevice::Text)) {
×
81
                        qWarning() << "[ObservingList] bookmarks list can not be saved. A file can not be open for reading and writing:"
×
82
                                   << QDir::toNativeSeparators(observingListJsonPath);
×
83
                        messageBox(q_("Error"), q_("Cannot open observingLists.json to write"));
×
84
                        return;
×
85
                }
86
                // Update the jsonMap and store
UNCOV
87
                jsonMap.insert(KEY_OBSERVING_LISTS, observingLists);
×
UNCOV
88
                jsonFile.resize(0);
×
89
                StelJsonParser::write(jsonMap, &jsonFile);
×
90
                jsonFile.flush();
×
91
                jsonFile.close();
×
92
        }
×
93

94
        delete ui;
×
UNCOV
95
        delete itemModel;
×
96
        ui = nullptr;
×
97
        itemModel = nullptr;
×
98
}
×
99

100
/*
101
 * Initialize the dialog widgets and connect the signals/slots.
102
*/
UNCOV
103
void ObsListDialog::createDialogContent()
×
104
{
105
        ui->setupUi(dialog);
×
106

107
        //Signals and slots
UNCOV
108
        connect(&StelApp::getInstance(), SIGNAL(languageChanged()), this, SLOT(retranslate()));
×
UNCOV
109
        connect(ui->titleBar, &TitleBar::closeClicked, this, &StelDialog::close);
×
110

111
        // Standard mode buttons: NewList/EditList/DeleteList
UNCOV
112
        connect(ui->newListButton,        SIGNAL(clicked()), this, SLOT(   newListButtonPressed()));
×
UNCOV
113
        connect(ui->editListButton,       SIGNAL(clicked()), this, SLOT(  editListButtonPressed()));
×
114
        connect(ui->deleteListButton,     SIGNAL(clicked()), this, SLOT(deleteListButtonPressed()));
×
115
        connect(ui->importListButton,     SIGNAL(clicked()), this, SLOT(importListButtonPressed()));
×
116
        connect(ui->exportListButton,     SIGNAL(clicked()), this, SLOT(exportListButtonPressed()));
×
117
        // Mark all objects of currentList in the sky
118
        connect(ui->highlightAllButton,   SIGNAL(clicked()), this, SLOT(highlightAll()));
×
UNCOV
119
        connect(ui->clearHighlightButton, SIGNAL(clicked()), this, SLOT(clearHighlights()));
×
120
        // Edits
121
        connect(ui->addObjectButton,      SIGNAL(clicked()), this, SLOT(   addObjectButtonPressed()));
×
UNCOV
122
        connect(ui->removeObjectButton,   SIGNAL(clicked()), this, SLOT(removeObjectButtonPressed()));
×
123
        connect(ui->saveButton,           SIGNAL(clicked()), this, SLOT(  saveButtonPressed()));
×
124
        connect(ui->cancelButton,         SIGNAL(clicked()), this, SLOT(cancelButtonPressed()));
×
125

126
        connect(ui->defaultListCheckBox, SIGNAL(clicked(bool)), this, SLOT(defaultClicked(bool)));
×
127

128
        // Allow loading one list entry
UNCOV
129
        connect(ui->treeView,           SIGNAL(doubleClicked(QModelIndex)), this, SLOT(selectAndGoToObject(QModelIndex)));
×
130

131
        switchEditMode(false, false); // start with view mode
×
132

133
        connectBoolProperty(ui->jdCheckBox,        "ObsListDialog.flagUseJD");
×
UNCOV
134
        connectBoolProperty(ui->locationCheckBox,  "ObsListDialog.flagUseLocation");
×
135
        connectBoolProperty(ui->landscapeCheckBox, "ObsListDialog.flagUseLandscape");
×
136
        connectBoolProperty(ui->fovCheckBox,       "ObsListDialog.flagUseFov");
×
137

138
        ui->obsListDirEdit->setText(StelFileMgr::getObsListDir());
×
UNCOV
139
        connect(ui->obsListDirEdit, SIGNAL(editingFinished()), this, SLOT(selectObsListDir()));
×
140
        connect(ui->obsListBrowseButton, SIGNAL(clicked()), this, SLOT(browseForObsListDir()));
×
141

142

143
        //obsListCombo settings: A change in the combobox loads the list.
UNCOV
144
        connect(ui->obsListComboBox, SIGNAL(activated(int)), this, SLOT(loadSelectedObservingList(int)));
×
145

146
        ui->treeView->setModel(itemModel);
×
UNCOV
147
        ui->treeView->header()->setSectionsMovable(false);
×
148
        ui->treeView->hideColumn(ColumnUUID);
×
149
        for (int c=ColumnDesignation; c<=ColumnLandscapeID; c++)
×
150
                ui->treeView->header()->setSectionResizeMode(c, QHeaderView::ResizeToContents);
×
151
        ui->treeView->header()->setStretchLastSection(true);
×
152
        //Enable the sort for columns
153
        ui->treeView->setSortingEnabled(true);
×
UNCOV
154
        connect(ui->treeView->header(), SIGNAL(sectionClicked(int)), this, SLOT(headerClicked(int)));
×
155

156
        // Load all observing lists from JSON.
157
        // We need to load the global list only once!
UNCOV
158
        QFile jsonFile(observingListJsonPath);
×
UNCOV
159
        if (!jsonFile.open(QIODevice::ReadWrite | QIODevice::Text)) {
×
160
                qWarning() << "[ObservingList] JSON list file can not be opened for reading and writing:"
×
161
                           << QDir::toNativeSeparators(observingListJsonPath);
×
162
                return;
×
163
        }
164
        if (jsonFile.size() > 0) {
×
UNCOV
165
                jsonMap = StelJsonParser::parse(jsonFile.readAll()).toMap();
×
166
                observingLists = jsonMap.value(KEY_OBSERVING_LISTS).toMap();
×
167
        }
168
        else
169
        {
170
                // begin with empty maps
UNCOV
171
                const QString olud=QUuid::createUuid().toString();
×
172
                jsonMap = { {KEY_SHORT_NAME       , SHORT_NAME_VALUE},
173
                            {KEY_VERSION          , FILE_VERSION},
UNCOV
174
                            {KEY_DEFAULT_LIST_OLUD, olud}};
×
UNCOV
175
                observingLists = QMap<QString, QVariant>();
×
176
                // Create one default empty list
177
                // Creation date
UNCOV
178
                const double JD = StelUtils::getJDFromSystem();
×
UNCOV
179
                const QString listCreationDate = StelUtils::julianDayToISO8601String(JD + core->getUTCOffset(JD) / 24.).replace("T", " ");
×
180
                QVariantMap emptyList = {
181
                        // Name, description, current date for the list, current sorting
UNCOV
182
                        {KEY_NAME,          qc_("new list", "default name for observing list if none is available")},
×
UNCOV
183
                        {KEY_DESCRIPTION,   QString()},
×
184
                        {KEY_SORTING,       QString()},
×
185
                        {KEY_CREATION_DATE, listCreationDate },
186
                        {KEY_LAST_EDIT,     listCreationDate }};
×
187

188
                observingLists.insert(olud, emptyList);
×
UNCOV
189
                jsonMap.insert(KEY_OBSERVING_LISTS, observingLists);
×
190
        }
×
191

192
        // For no regression we must take into account the legacy bookmarks file
UNCOV
193
        QFile jsonBookmarksFile(bookmarksJsonPath);
×
UNCOV
194
        if (jsonBookmarksFile.exists())
×
195
        {
196
                //qDebug() << "Old Bookmarks found: Try if we need to process/import them";
UNCOV
197
                if (!checkIfBookmarksListExists())
×
198
                {
199
                        //qDebug() << "No bookmark list so far. Importing...";
UNCOV
200
                        QHash<QString, observingListItem> bookmarksForImport=loadBookmarksFile(jsonBookmarksFile);
×
UNCOV
201
                        saveBookmarksHashInObservingLists(bookmarksForImport);
×
202
                        jsonMap.insert(KEY_OBSERVING_LISTS, observingLists); // Update the global map
×
203
                }
×
204
                //else
205
                //        qDebug() << "Bookmark list exists. We can skip the import.";
206

UNCOV
207
                jsonFile.resize(0);
×
UNCOV
208
                StelJsonParser::write(jsonMap, &jsonFile);
×
209
                jsonFile.flush();
×
210
                jsonFile.close();
×
211
                tainted=false;
×
212
        }
213
        // Now we certainly have a json file and have parsed everything that exists.
UNCOV
214
        defaultOlud = jsonMap.value(KEY_DEFAULT_LIST_OLUD).toString();
×
UNCOV
215
        loadListNames(); // also populate Combobox and make sure at least some defaultOlud exists.
×
216
        loadDefaultList();
×
217
}
×
218

219
void ObsListDialog::browseForObsListDir()
×
220
{
221
        const QString &oldObsListDir = StelFileMgr::getObsListDir();
×
UNCOV
222
        QString newObsListDir = QFileDialog::getExistingDirectory(&StelMainView::getInstance(), q_("Select observing lists directory"), oldObsListDir, QFileDialog::ShowDirsOnly);
×
223

224
        if (!newObsListDir.isEmpty()) {
×
225
                // remove trailing slash
226
                if (newObsListDir.right(1) == "/")
×
UNCOV
227
                        newObsListDir = newObsListDir.left(newObsListDir.length()-1);
×
228

229
                ui->obsListDirEdit->setText(newObsListDir);
×
UNCOV
230
                selectObsListDir();
×
231
        }
232
}
×
233

234
void ObsListDialog::selectObsListDir()
×
235
{
236
        QString dir = ui->obsListDirEdit->text();
×
237
        try
238
        {
UNCOV
239
                StelFileMgr::setObsListDir(dir);
×
UNCOV
240
                QSettings* conf = StelApp::getInstance().getSettings();
×
241
                conf->setValue("main/observinglists_dir", dir);
×
242
        }
243
        catch (std::runtime_error& e)
×
244
        {
245
                Q_UNUSED(e)
246
                // nop
247
                // this will happen when people are only half way through typing dirs
UNCOV
248
        }
×
UNCOV
249
}
×
250

251
/*
252
 * Check if bookmarks list already exists in observing list file,
253
 * in fact if the file of bookmarks has already be loaded.
254
*/
UNCOV
255
bool ObsListDialog::checkIfBookmarksListExists()
×
256
{
257
        QMapIterator<QString,QVariant>it(observingLists);
×
UNCOV
258
        while(it.hasNext())
×
259
        {
260
                it.next();
×
UNCOV
261
                QVariantMap map = it.value().toMap();
×
262
                QString listName = map.value(KEY_NAME).toString();
×
263

264
                if (BOOKMARKS_LIST_NAME == listName)
×
UNCOV
265
                        return true;
×
266
        }
×
267
        return false;
×
268
}
×
269

270
/*
271
 * Retranslate dialog
272
*/
UNCOV
273
void ObsListDialog::retranslate()
×
274
{
275
        if (dialog)
×
276
        {
277
                ui->retranslateUi(dialog);
×
UNCOV
278
                setObservingListHeaderNames();
×
279
        }
280
}
×
281

282
/*
283
 * Set the header for the observing list table (obsListTreeView)
284
*/
UNCOV
285
void ObsListDialog::setObservingListHeaderNames()
×
286
{
287
        const QStringList headerStrings = {
288
                "UUID",                     // Hidden column
289
                q_("Object designation"),   // English name and/or catalog number
290
                q_("Object name"),          // Localized name
291
                q_("Type"),                 // Localized type description (not just class name)
292
                q_("Right ascension"),      // J2000.0 RA
293
                q_("Declination"),          // J2000.0 DE
294
                q_("Magnitude"),            // visual magnitude
295
                q_("Constellation"),        // IAU constellation code
296
                q_("Date"),                 // date string (if stored)
297
                q_("Location"),             // location (if stored)
298
                q_("Landscape")             // landscape ID (if stored)
UNCOV
299
        };
×
UNCOV
300
        Q_ASSERT(headerStrings.length()==ColumnCount);
×
301
        itemModel->setHorizontalHeaderLabels(headerStrings);
×
302
}
×
303

304
/*
305
 * Add row in the obsListListModel
306
*/
UNCOV
307
void ObsListDialog::addModelRow(const QString &olud, const QString &designation, const QString &nameI18n,
×
308
                                const QString &typeI18n, const QString &ra,
309
                                const QString &dec, const QString &magnitude, const QString &constellation,
310
                                const QString &date, const QString &location, const QString &landscapeID)
311
{
UNCOV
312
        const int number=itemModel->rowCount();
×
UNCOV
313
        QStandardItem *item = nullptr;
×
314

315
        item = new QStandardItem(olud);
×
UNCOV
316
        item->setEditable(false);
×
317
        itemModel->setItem(number, ColumnUUID, item);
×
318

319
        item = new QStandardItem(designation);
×
UNCOV
320
        item->setEditable(false);
×
321
        itemModel->setItem(number, ColumnDesignation, item);
×
322

323
        item = new QStandardItem(nameI18n);
×
UNCOV
324
        item->setEditable(false);
×
325
        itemModel->setItem(number, ColumnNameI18n, item);
×
326

327
        item = new QStandardItem(typeI18n);
×
UNCOV
328
        item->setEditable(false);
×
329
        itemModel->setItem(number, ColumnType, item);
×
330

331
        item = new QStandardItem(ra);
×
UNCOV
332
        item->setEditable(false);
×
333
        itemModel->setItem(number, ColumnRa, item);
×
334

335
        item = new QStandardItem(dec);
×
UNCOV
336
        item->setEditable(false);
×
337
        itemModel->setItem(number, ColumnDec, item);
×
338

339
        item = new QStandardItem(magnitude);
×
UNCOV
340
        item->setEditable(false);
×
341
        itemModel->setItem(number, ColumnMagnitude, item);
×
342

343
        item = new QStandardItem(constellation);
×
UNCOV
344
        item->setEditable(false);
×
345
        itemModel->setItem(number, ColumnConstellation, item);
×
346

347
        item = new QStandardItem(date);
×
UNCOV
348
        item->setEditable(false);
×
349
        itemModel->setItem(number, ColumnDate, item);
×
350

351
        item = new QStandardItem(location);
×
UNCOV
352
        item->setEditable(false);
×
353
        itemModel->setItem(number, ColumnLocation, item);
×
354

355
        item = new QStandardItem(landscapeID);
×
UNCOV
356
        item->setEditable(false);
×
357
        itemModel->setItem(number, ColumnLandscapeID, item);
×
358

359
        for (int i = 0; i < ColumnCount; ++i)
×
UNCOV
360
                ui->treeView->resizeColumnToContents(i);
×
361
}
×
362

363
/*
364
 * Load the lists names from jsonMap,
365
 * Populate the list names into combo box and extract defaultOlud
366
*/
UNCOV
367
void ObsListDialog::loadListNames(const QString& listID)
×
368
{
369
        listNames.clear();
×
UNCOV
370
        QVariantMap::iterator i;
×
371
        // Clean list of OL to avoid duplicates
372
        ui->obsListComboBox->clear();
×
373

374
        // Add the list name and OLUD (as item data) into the ComboBox.
UNCOV
375
        for (i = observingLists.begin(); i != observingLists.end(); ++i) {
×
UNCOV
376
                const QString &listUuid = i.key();
×
377
                if (i.value().canConvert<QVariantMap>()) // if this looks like an actual obsList?
×
378
                {
379
                        QVariant var = i.value();
×
UNCOV
380
                        QVariantMap data = var.value<QVariantMap>();
×
381
                        QString listName = data.value(KEY_NAME).toString();
×
382
                        listNames.append(listName);
×
383
                        ui->obsListComboBox->addItem(listName, listUuid);
×
384
                }
×
385
        }
386
        ui->obsListComboBox->model()->sort(0);
×
UNCOV
387
        if (!listID.isEmpty())
×
388
        {
389
                // select observing list by OLUD
UNCOV
390
                int idx = ui->obsListComboBox->findData(listID, Qt::UserRole);
×
UNCOV
391
                if (idx<0)
×
392
                        idx = 0;
×
393
                ui->obsListComboBox->setCurrentIndex(idx);
×
394
        }
395

396
        // If defaultOlud list not found, set first list as default.
UNCOV
397
        if (!observingLists.contains(defaultOlud))
×
398
        {
399
                qDebug() << "populateListNameInComboBox: Cannot find defaultListOlud" << defaultOlud << ". Setting to first list.";
×
UNCOV
400
                defaultOlud = observingLists.firstKey();
×
401
                jsonMap.insert(KEY_DEFAULT_LIST_OLUD, defaultOlud);
×
402
                tainted=true;
×
403
        }
404
}
×
405

406
/*
407
 * Load the default list
408
*/
UNCOV
409
void ObsListDialog::loadDefaultList()
×
410
{
411
        if (defaultOlud != "")
×
412
        {
413
                int index = ui->obsListComboBox->findData(defaultOlud);
×
UNCOV
414
                if (index != -1)
×
415
                {
416
                        ui->obsListComboBox->setCurrentIndex(index);
×
UNCOV
417
                        selectedOlud = defaultOlud;
×
418
                }
419
        }
420
        else
421
        {
422
                // If there is no default list we load the current, or the first list in the combo box
UNCOV
423
                int currentIndex = ui->obsListComboBox->currentIndex();
×
UNCOV
424
                if (currentIndex != -1)
×
425
                {
426
                        currentIndex=0;
×
UNCOV
427
                        ui->obsListComboBox->setCurrentIndex(0);
×
428
                }
429
                selectedOlud = ui->obsListComboBox->itemData(currentIndex).toString();
×
UNCOV
430
                defaultOlud = selectedOlud;
×
431
                jsonMap.insert(KEY_DEFAULT_LIST_OLUD, defaultOlud);
×
432
                tainted=true;
×
433
        }
434
        loadSelectedList();
×
UNCOV
435
}
×
436

437
/*
438
 * Load the selected observing list (selectedOlud) into the dialog.
439
*/
UNCOV
440
void ObsListDialog::loadSelectedList()
×
441
{
442
        // At this point selectedOlud must be set
UNCOV
443
        Q_ASSERT(selectedOlud.length()>0);
×
444

445
        bool conversionError=false;
×
446
        // We must keep selection for the user. It is not enough to store/restore the existingSelection.
447
        // The QList<StelObjectP> objects are apparently volatile. We must retrieve the actual object.
UNCOV
448
        const QList<StelObjectP>&existingSelection = objectMgr->getSelectedObject();
×
UNCOV
449
        QList<StelObjectP> existingSelectionToRestore;
×
450
        if (existingSelection.length()>0)
×
451
        {
452
                existingSelectionToRestore.append(existingSelection.at(0));
×
453
        }
454

455
        // Check or not default list checkbox information
UNCOV
456
        ui->defaultListCheckBox->setChecked(selectedOlud == defaultOlud);
×
457

458
        QVariantMap observingListMap = observingLists.value(selectedOlud).toMap();
×
459

460
        QVariantList listOfObjects;
×
461

462
        // Display description and creation date
UNCOV
463
        currentListName=observingListMap.value(KEY_NAME).toString();
×
UNCOV
464
        ui->listNameLineEdit->setText(currentListName);
×
465
        ui->descriptionLineEdit->setText(observingListMap.value(KEY_DESCRIPTION).toString());
×
466
        ui->creationDateLineEdit->setText(observingListMap.value(KEY_CREATION_DATE).toString());
×
467
        ui->lastEditLineEdit->setText(observingListMap.value(KEY_LAST_EDIT, observingListMap.value(KEY_CREATION_DATE)).toString());
×
468

469
        if (observingListMap.value(KEY_OBJECTS).canConvert<QVariantList>())
×
470
        {
471
                QVariant data = observingListMap.value(KEY_OBJECTS);
×
UNCOV
472
                listOfObjects = data.value<QVariantList>();
×
473
        }
×
474
        else
475
        {
UNCOV
476
                qCritical() << "[ObservingList] conversion error in list " << currentListName << "from" << observingListMap.value(KEY_CREATION_DATE).toString();
×
UNCOV
477
                qCritical() << "Cannot convert this objects entry:" << observingListMap.value(KEY_OBJECTS);
×
478
                conversionError=true;
×
479
        }
480

481
        // Clear model
UNCOV
482
        itemModel->removeRows(0, itemModel->rowCount()); // don't use clear() here!
×
UNCOV
483
        currentItemCollection.clear();
×
484

485
        if (!listOfObjects.isEmpty())
×
486
        {
487
                for (const QVariant &object: listOfObjects)
×
488
                {
489
                        if (object.canConvert<QVariantMap>())
×
490
                        {
491
                                QVariantMap objectMap = object.value<QVariantMap>();
×
492

493
                                observingListItem item;
×
UNCOV
494
                                const QString objectUUID = QUuid::createUuid().toString();
×
495
                                item.designation = objectMap.value(KEY_DESIGNATION).toString();  // This is the common name or catalog number (with catalog ID)
×
496
                                item.name = objectMap.value(KEY_NAME).toString();          // Preliminary: Do not rely on name in the JSON file. It may have changed in Stellarium's name lists! Retrieve name from the actual object later.
×
497
                                item.nameI18n = objectMap.value(KEY_NAME_I18N).toString(); // Preliminary: Do not rely on translated name in the JSON file. It may be in the wrong language or may have changed in Stellarium's name lists! Retrieve translated name from the actual object later.
×
498
                                item.objClass = objectMap.value(KEY_TYPE).toString();
×
499
                                item.objTypeI18n  = objectMap.value(KEY_OBJECTS_TYPE).toString(); // Preliminary: Do not rely on this translated string! Re-retrieve later
×
500
                                item.ra  = objectMap.value(KEY_RA).toString();
×
501
                                item.dec = objectMap.value(KEY_DEC).toString();
×
502
                                QList<StelObjectP> selectedObject;
×
503

504
                                if (objectMgr->findAndSelect(item.designation, item.objClass) && !objectMgr->getSelectedObject().isEmpty())
×
505
                                {
506
                                        //qDebug() << "ObsList: found an object of objClass" << item.objClass << "for" << item.designation;
UNCOV
507
                                        selectedObject = objectMgr->getSelectedObject();
×
508
                                }
509
                                else // try findAndSelect with any type. Note that this may lead to confusion!
UNCOV
510
                                        if (objectMgr->findAndSelect(item.designation) && !objectMgr->getSelectedObject().isEmpty())
×
511
                                {
512
                                        selectedObject = objectMgr->getSelectedObject();
×
513
                                        //qDebug() << "Changing item.objClass " << item.objClass << "to" << selectedObject[0]->getType();
514
                                        item.objClass = selectedObject[0]->getType();
×
515
                                }
516

UNCOV
517
                                if (!selectedObject.isEmpty())
×
518
                                {
519
                                        double ra, dec;
UNCOV
520
                                        StelUtils::rectToSphe(&ra, &dec, selectedObject[0]->getJ2000EquatorialPos(core));
×
521

522
                                        if (item.ra.isEmpty())
×
UNCOV
523
                                                item.ra = StelUtils::radToHmsStr(ra, false).trimmed();
×
524
                                        if (item.dec.isEmpty())
×
525
                                                item.dec = StelUtils::radToDmsStr(dec, false).trimmed();
×
526
                                        item.objTypeI18n = selectedObject[0]->getObjectTypeI18n();
×
527
                                        item.name=selectedObject[0]->getEnglishName();
×
528
                                        item.nameI18n=selectedObject[0]->getNameI18n();
×
529
                                }
530
                                else
531
                                {
UNCOV
532
                                        qWarning() << "[ObservingList] object: " << item.designation << " not found or empty.";
×
UNCOV
533
                                        qWarning() << "item.objType given as:" << item.objTypeI18n;
×
534
                                        qWarning() << "item.objClass given as:" << item.objClass;
×
535
                                }
536

UNCOV
537
                                item.magnitude = objectMap.value(KEY_MAGNITUDE).toString();
×
UNCOV
538
                                item.constellation = objectMap.value(KEY_CONSTELLATION).toString();
×
539

540
                                // Julian Day / Date
UNCOV
541
                                item.jd = objectMap.value(KEY_JD).toDouble();
×
UNCOV
542
                                QString dateStr;
×
543
                                if (item.jd != 0.)
×
544
                                        dateStr = StelUtils::julianDayToISO8601String(item.jd + core->getUTCOffset(item.jd) / 24.).replace("T", " ");
×
545

546
                                // Location, landscapeID, FoV (may be empty)
UNCOV
547
                                item.location = objectMap.value(KEY_LOCATION).toString();
×
UNCOV
548
                                item.landscapeID = objectMap.value(KEY_LANDSCAPE_ID).toString();
×
549

550
                                const QSettings* conf  = StelApp::getInstance().getSettings();
×
UNCOV
551
                                const double minFov=conf->value("navigation/min_fov", 1./3600.).toDouble();
×
552
                                item.fov = qBound(minFov, objectMap.value(KEY_FOV).toDouble(), 360.);
×
553

554
                                // Visible flag
UNCOV
555
                                item.isVisibleMarker = objectMap.value(KEY_IS_VISIBLE_MARKER).toBool();
×
556

557
                                QString LocationStr;
×
UNCOV
558
                                if (!item.location.isEmpty())
×
559
                                {
560
                                        StelLocation loc=StelApp::getInstance().getLocationMgr().locationForString(item.location);
×
UNCOV
561
                                        LocationStr=loc.name;
×
562
                                }
×
563

564
                                addModelRow(objectUUID,
×
565
                                            item.designation,
566
                                            item.nameI18n,
567
                                            item.objTypeI18n,
568
                                            item.ra,
569
                                            item.dec,
570
                                            item.magnitude,
571
                                            item.constellation,
572
                                            dateStr,
573
                                            LocationStr,
574
                                            item.landscapeID);
575

UNCOV
576
                                currentItemCollection.insert(objectUUID, item);
×
UNCOV
577
                        }
×
578
                        else
579
                        {
UNCOV
580
                                qCritical() << "[ObservingList] conversion error for object: "  << object;
×
UNCOV
581
                                conversionError=true;
×
582
                        }
583
                }
584
        }
585

UNCOV
586
        if (conversionError)
×
587
        {
588
                QMessageBox::warning(&StelMainView::getInstance(), q_("Attention!"), q_("Error during conversion. Please see logfile for details."));
×
UNCOV
589
                return;
×
590
        }
591

592
        // Sorting for the objects list.
UNCOV
593
        QString sortingBy = observingListMap.value(KEY_SORTING).toString();
×
UNCOV
594
        if (!sortingBy.isEmpty())
×
595
                sortObsListTreeViewByColumnName(sortingBy);
×
596

597
        // Restore selection that was active before calling this
UNCOV
598
        if (existingSelectionToRestore.length()>0)
×
UNCOV
599
                objectMgr->setSelectedObject(existingSelectionToRestore, StelModule::ReplaceSelection);
×
600
        else
601
                objectMgr->unSelect();
×
UNCOV
602
}
×
603

604
/*
605
 * Load the bookmarks of bookmarks.json file into observing lists file
606
*/
UNCOV
607
QHash<QString, ObsListDialog::observingListItem> ObsListDialog::loadBookmarksFile(QFile &file)
×
608
{
609
        qWarning() << "DEPRECATION WARNING";
×
UNCOV
610
        qWarning() << "  Loading old-style Bookmarks file. This file format is deprecated.";
×
611
        qWarning() << "  If you are loading this as a separate file, ";
×
612
        qWarning() << "  Please update the file (re-export the list into *.sol format).";
×
613

614
        QHash<QString, observingListItem> bookmarksItemHash;
×
615

UNCOV
616
        if (!file.open(QIODevice::ReadOnly)) {
×
617
                qWarning() << "[ObservingList] cannot open" << QDir::toNativeSeparators(bookmarksJsonPath);
×
618
        }
619
        else
620
        {
UNCOV
621
                const double currentJD=core->getJDOfLastJDUpdate();// Restore at end
×
UNCOV
622
                const qint64 millis = core->getMilliSecondsOfLastJDUpdate();
×
623

624
                // We must keep selection for the user!
625
                const QList<StelObjectP>&existingSelection = objectMgr->getSelectedObject();
×
UNCOV
626
                QList<StelObjectP> existingSelectionToRestore;
×
UNCOV
627
                if (existingSelection.length()>0)
×
628
                {
629
                        existingSelectionToRestore.append(existingSelection.at(0));
×
630
                }
631

632
                try {
UNCOV
633
                        bool importWarning=false;
×
UNCOV
634
                        QVariantMap map = StelJsonParser::parse(file.readAll()).toMap();
×
UNCOV
635
                        file.close();
×
636
                        QVariantMap bookmarksMap = map.value(KEY_BOOKMARKS).toMap();
×
637

638
                        QMapIterator<QString,QVariant>it(bookmarksMap);
×
UNCOV
639
                        while(it.hasNext())
×
640
                        {
641
                                it.next();
×
642

643
                                QVariantMap bookmarkMap = it.value().toMap();
×
UNCOV
644
                                observingListItem item;
×
645

646
                                // Name
UNCOV
647
                                item.designation = bookmarkMap.value(KEY_NAME).toString();
×
UNCOV
648
                                QString nameI18n = bookmarkMap.value(KEY_NAME_I18N).toString();
×
649
                                item.nameI18n = nameI18n.isEmpty() ? DASH : nameI18n;
×
650

651
                                // We need to select the object to add additional information that is not in the Bookmark file
UNCOV
652
                                if (objectMgr->findAndSelect(item.designation) && !objectMgr->getSelectedObject().isEmpty()) {
×
UNCOV
653
                                        const QList<StelObjectP> &selectedObject = objectMgr->getSelectedObject();
×
654

655
                                        item.objClass = selectedObject[0]->getType(); // Assign class name
×
UNCOV
656
                                        item.objTypeI18n = selectedObject[0]->getObjectTypeI18n(); // Assign a detailed object type description
×
657
                                        item.name = selectedObject[0]->getEnglishName();
×
658
                                        item.nameI18n = selectedObject[0]->getNameI18n();
×
659
                                        item.jd = bookmarkMap.value(KEY_JD).toDouble();
×
660
                                        if (item.jd!=0.)
×
661
                                        {
662
                                                core->setJD(item.jd);
×
UNCOV
663
                                                core->update(0.); // Force position updates
×
664
                                        }
665

666
                                        // Ra & Dec - ra and dec are not empty in case of Custom Object
UNCOV
667
                                        item.ra = bookmarkMap.value(KEY_RA).toString();
×
UNCOV
668
                                        item.dec = bookmarkMap.value(KEY_DEC).toString();
×
669
                                        if (item.ra.isEmpty() || item.dec.isEmpty()) {
×
670
                                                double ra, dec;
671
                                                StelUtils::rectToSphe(&ra, &dec, selectedObject[0]->getJ2000EquatorialPos(core));
×
UNCOV
672
                                                item.ra = StelUtils::radToHmsStr(ra, false).trimmed();
×
673
                                                item.dec = StelUtils::radToDmsStr(dec, false).trimmed();
×
674
                                        }
675
                                        item.magnitude = getMagnitude(selectedObject, core);
×
676
                                        // Several data items were not part of the original bookmarks, so we have no entry.
677
                                        const Vec3d posNow = selectedObject[0]->getEquinoxEquatorialPos(core);
×
UNCOV
678
                                        item.constellation = core->getIAUConstellation(posNow);
×
679
                                        item.location = bookmarkMap.value(KEY_LOCATION).toString();
×
680
                                        // No landscape in original bookmarks. Just leave empty.
681
                                        //item.landscapeID = bookmarkData.value(KEY_LANDSCAPE_ID).toString();
UNCOV
682
                                        double bmFov = bookmarkMap.value(KEY_FOV).toDouble();
×
UNCOV
683
                                        if (bmFov>1.e-10) // FoV may look like 3.121251e-310, which is bogus.
×
684
                                                item.fov=bmFov;
×
685
                                        item.isVisibleMarker = bookmarkMap.value(KEY_IS_VISIBLE_MARKER, false).toBool();
×
686

687
                                        bookmarksItemHash.insert(it.key(), item);
×
688
                                }
689
                                else
690
                                {
UNCOV
691
                                        qWarning() << "Bookmark import: Cannot find Object " << item.designation << "(" << nameI18n << ")";
×
UNCOV
692
                                        importWarning=true;
×
693
                                }
694
                        }
×
UNCOV
695
                        if (importWarning)
×
696
                        {
697
                                qWarning() << "Some bookmarked objects in file" << file.fileName() << "were not found.";
×
UNCOV
698
                                qWarning() << "If these are Solar System objects, make sure you have imported the respective orbital elements, "
×
699
                                              "and the file loads without warnings in the current version.";
×
700
                                messageBox(q_("Note"), q_("Some bookmarked objects were not found. See logfile for details."));
×
701
                        }
702
                }
×
UNCOV
703
                catch (std::runtime_error &e)
×
704
                {
705
                        qWarning() << "[ObservingList] Load bookmarks in observing list: File format is wrong! Error: " << e.what();
×
UNCOV
706
                }
×
707
                // Restore selection that was active before calling this
708
                if (existingSelectionToRestore.length()>0)
×
UNCOV
709
                        objectMgr->setSelectedObject(existingSelectionToRestore, StelModule::ReplaceSelection);
×
710
                else
711
                        objectMgr->unSelect();
×
712

713
                core->setJD(currentJD);
×
UNCOV
714
                core->setMilliSecondsOfLastJDUpdate(millis); // restore millis.
×
715
                core->update(0); // enforce update to the previous positions
×
716
        }
×
717
        return bookmarksItemHash;
×
718
}
×
719

720
/*
721
 * Save the bookmarks into observingLists QVariantMap
722
*/
UNCOV
723
QString ObsListDialog::saveBookmarksHashInObservingLists(const QHash<QString, observingListItem> &bookmarksHash)
×
724
{
725
        // Creation date
UNCOV
726
        double JD = StelUtils::getJDFromSystem(); // Mark with current system time
×
UNCOV
727
        QString listCreationDate = StelUtils::julianDayToISO8601String(JD + core->getUTCOffset(JD) / 24.).replace("T", " ");
×
728

729
        QVariantMap bookmarksObsList = {
730
                {KEY_NAME,          BOOKMARKS_LIST_NAME},
731
                {KEY_DESCRIPTION,   BOOKMARKS_LIST_DESCRIPTION},
732
                {KEY_CREATION_DATE, listCreationDate},
733
                {KEY_LAST_EDIT,     listCreationDate},
UNCOV
734
                {KEY_SORTING,       SORTING_BY_NAME}};
×
735

736
        // Add actual list of (former) bookmark entries
UNCOV
737
        QVariantList objects;
×
UNCOV
738
        QHashIterator<QString, observingListItem> it(bookmarksHash);
×
739
        while (it.hasNext())
×
740
        {
741
                it.next();
×
UNCOV
742
                observingListItem item = it.value();
×
743
                objects.push_back(item.toVariantMap());
×
744
        }
×
745
        bookmarksObsList.insert(KEY_OBJECTS, objects);
×
746

747
        QList<QString> keys = bookmarksHash.keys();
×
UNCOV
748
        QString bookmarkListOlud= (keys.empty() ? QUuid::createUuid().toString() : keys.at(0));
×
749

750
        observingLists.insert(bookmarkListOlud, bookmarksObsList);
×
UNCOV
751
        return bookmarkListOlud;
×
752
}
×
753

754
/*
755
 * Select and go to object
756
*/
UNCOV
757
void ObsListDialog::selectAndGoToObject(QModelIndex index)
×
758
{
759
    // Map the index from the proxy to the source model.
UNCOV
760
    QSortFilterProxyModel* proxy = qobject_cast<QSortFilterProxyModel*>(ui->treeView->model());
×
UNCOV
761
    QModelIndex sourceIndex = proxy ? proxy->mapToSource(index) : index;
×
762

763
    QStandardItem *selectedItem = itemModel->itemFromIndex(sourceIndex);
×
UNCOV
764
    if (!selectedItem)
×
765
        return;
×
766
    int rowNumber = selectedItem->row();
×
767

768
    QStandardItem *uuidItem = itemModel->item(rowNumber, ColumnUUID);
×
UNCOV
769
    if (!uuidItem)
×
770
        return;
×
771
    QString itemUuid = uuidItem->text();
×
772
    observingListItem item = currentItemCollection.value(itemUuid);
×
773

774
        // Load landscape/location before dealing with the object: It could be a view from another planet!
775
        // We load stored landscape/location if the respective checkbox is checked.
UNCOV
776
        if (getFlagUseLandscape() && !item.landscapeID.isEmpty())
×
UNCOV
777
                GETSTELMODULE(LandscapeMgr)->setCurrentLandscapeID(item.landscapeID, 0);
×
778
        if (getFlagUseLocation() && !item.location.isEmpty())
×
779
        {
780
                StelLocation loc=StelApp::getInstance().getLocationMgr().locationForString(item.location);
×
UNCOV
781
                if (loc.isValid())
×
782
                        core->moveObserverTo(loc);
×
783
                else
784
                        qWarning() << "ObservingLists: Cannot retrieve valid location for" << item.location;
×
UNCOV
785
        }
×
786
        // We also use stored jd only if the checkbox JD is checked.
787
        if (getFlagUseJD() && item.jd != 0.0)
×
UNCOV
788
                core->setJD(item.jd);
×
789

790
        StelMovementMgr *mvmgr = GETSTELMODULE(StelMovementMgr);
×
791
        //objectMgr->unSelect();
792

UNCOV
793
        bool objectFound = objectMgr->findAndSelect(item.designation); // TODO: We should prefer to use findAndSelect(item.designation, item.objClass). But what are the implications for markers?
×
UNCOV
794
        if (!item.ra.isEmpty() && !item.dec.isEmpty() && (!objectFound || item.designation.contains("marker", Qt::CaseInsensitive))) {
×
795
                Vec3d pos;
×
796
                StelUtils::spheToRect(StelUtils::getDecAngle(item.ra.trimmed()), StelUtils::getDecAngle(item.dec.trimmed()), pos);
×
797
                if (item.designation.contains("marker", Qt::CaseInsensitive))
×
798
                {
799
                        // Add a custom object on the sky
UNCOV
800
                        GETSTELMODULE(CustomObjectMgr)->addCustomObject(item.designation, pos, item.isVisibleMarker);
×
UNCOV
801
                        objectFound = objectMgr->findAndSelect(item.designation);
×
802
                }
803
                else
804
                {
805
                        // The unnamed stars
UNCOV
806
                        StelObjectP sobj=nullptr;
×
UNCOV
807
                        const StelProjectorP prj = core->getProjection(StelCore::FrameJ2000);
×
808
                        double fov = (item.fov > 0.0 ? item.fov : 5.0);
×
809

810
                        mvmgr->zoomTo(fov, 0.0);
×
UNCOV
811
                        mvmgr->moveToJ2000(pos, mvmgr->mountFrameToJ2000(Vec3d(0., 0., 1.)), 0.0);
×
812

813
                        QList<StelObjectP> candidates = GETSTELMODULE(StarMgr)->searchAround(pos, 0.5, core);
×
UNCOV
814
                        if (candidates.empty()) { // The FOV is too big, let's reduce it to see dimmer objects.
×
815
                                mvmgr->zoomTo(0.5 * fov, 0.0);
×
816
                                candidates = GETSTELMODULE(StarMgr)->searchAround(pos, 0.5, core);
×
817
                        }
818

UNCOV
819
                        Vec3d winpos;
×
UNCOV
820
                        prj->project(pos, winpos);
×
821
                        double xpos = winpos[0];
×
822
                        double ypos = winpos[1];
×
823
                        double bestCandDistSq = 1.e6;
×
824
                        for (const auto &obj: candidates)
×
825
                        {
826
                                prj->project(obj->getJ2000EquatorialPos(core), winpos);
×
UNCOV
827
                                double sqrDistance = (xpos - winpos[0]) * (xpos - winpos[0]) + (ypos - winpos[1]) * (ypos - winpos[1]);
×
828
                                if (sqrDistance < bestCandDistSq)
×
829
                                {
830
                                        bestCandDistSq = sqrDistance;
×
UNCOV
831
                                        sobj = obj;
×
832
                                }
833
                        }
UNCOV
834
                        if (sobj)
×
UNCOV
835
                                objectFound = objectMgr->setSelectedObject(sobj);
×
836
                }
×
837
        }
838

UNCOV
839
        if (objectFound) {
×
UNCOV
840
                const QList<StelObjectP> newSelected = objectMgr->getSelectedObject();
×
841
                if (!newSelected.empty())
×
842
                {
843
                        const float amd = mvmgr->getAutoMoveDuration();
×
UNCOV
844
                        mvmgr->moveToObject(newSelected[0], amd);
×
845
                        mvmgr->setFlagTracking(true);
×
846
                        // We load stored FoV if the FoV checkbox is checked.
847
                        if (getFlagUseFov() && item.fov>1e-10) {
×
UNCOV
848
                                GETSTELMODULE(StelMovementMgr)->zoomTo(item.fov, amd);
×
849
                        }
850
                }
UNCOV
851
        }
×
UNCOV
852
}
×
853

854
/*
855
 * Method called when a list name is selected in the combobox
856
*/
UNCOV
857
void ObsListDialog::loadSelectedObservingList(int selectedIndex)
×
858
{
859
        //ui->editListButton->setEnabled(true);
860
        //ui->deleteListButton->setEnabled(true);
UNCOV
861
        selectedOlud = ui->obsListComboBox->itemData(selectedIndex).toString();
×
UNCOV
862
        loadSelectedList();
×
863
}
×
864

865
/*
866
 * Slot for button highlightAllButton: show all objects of active list.
867
*/
UNCOV
868
void ObsListDialog::highlightAll()
×
869
{
870
        // We must keep selection for the user. It is not enough to store/restore the existingSelection.
871
        // The QList<StelObjectP> objects are apparently volatile. We must retrieve the actual object.
UNCOV
872
        const QList<StelObjectP>&existingSelection = objectMgr->getSelectedObject();
×
UNCOV
873
        QList<StelObjectP> existingSelectionToRestore;
×
874
        if (existingSelection.length()>0)
×
875
        {
876
                existingSelectionToRestore.append(existingSelection.at(0));
×
877
        }
878

UNCOV
879
        QList<Vec3d> highlights;
×
UNCOV
880
        clearHighlights(); // Enable fool protection
×
881
        const int fontSize = StelApp::getInstance().getScreenFontSize();
×
882
        HighlightMgr *hlMgr = GETSTELMODULE(HighlightMgr);
×
883
        const QString color = hlMgr->getColor().toHtmlColor();
×
884
        float distance = hlMgr->getMarkersSize();
×
885

886
        for (const auto &item: std::as_const(currentItemCollection)) {
×
UNCOV
887
                const QString name = item.designation;
×
888
                const QString raStr = item.ra.trimmed();
×
889
                const QString decStr = item.dec.trimmed();
×
890

891
                Vec3d pos;
×
892
                bool usablePosition;
893
                if (!raStr.isEmpty() && !decStr.isEmpty())
×
894
                {
895
                        StelUtils::spheToRect(StelUtils::getDecAngle(raStr), StelUtils::getDecAngle(decStr), pos);
×
UNCOV
896
                        usablePosition = true;
×
897
                }
898
                else
899
                {
UNCOV
900
                        usablePosition = objectMgr->findAndSelect(name);
×
UNCOV
901
                        if (usablePosition) {
×
902
                                const QList<StelObjectP> &selected = objectMgr->getSelectedObject();
×
903
                                pos = selected[0]->getJ2000EquatorialPos(core);
×
904
                        }
905
                }
UNCOV
906
                if (usablePosition)
×
UNCOV
907
                        highlights.append(pos);
×
908

909
                // Add labels for named highlights (name in top right corner)
UNCOV
910
                if (!raStr.isEmpty() && !decStr.isEmpty()) // We may have a position for a timestamped event
×
UNCOV
911
                        highlightLabelIDs.append(labelMgr->labelEquatorial(name, raStr, decStr, true, fontSize, color, "NE", distance));
×
912
                else
913
                        highlightLabelIDs.append(labelMgr->labelObject(name, name, true, fontSize, color, "NE", distance));
×
UNCOV
914
        }
×
915

916
        hlMgr->fillHighlightList(highlights);
×
917

918
        // Restore selection that was active before calling this
UNCOV
919
        if (existingSelectionToRestore.length()>0)
×
UNCOV
920
                objectMgr->setSelectedObject(existingSelectionToRestore, StelModule::ReplaceSelection);
×
921
        else
922
                objectMgr->unSelect();
×
UNCOV
923
}
×
924

925
/*
926
 * Clear highlights
927
*/
UNCOV
928
void ObsListDialog::clearHighlights()
×
929
{
930
        GETSTELMODULE(HighlightMgr)->cleanHighlightList();
×
931
        // Clear labels
932
        for (int l: highlightLabelIDs) {
×
UNCOV
933
                labelMgr->deleteLabel(l);
×
934
        }
935
        highlightLabelIDs.clear();
×
UNCOV
936
}
×
937

938
/*
939
 * Slot for button newListButton
940
*/
UNCOV
941
void ObsListDialog::newListButtonPressed()
×
942
{
943
        selectedOlud=QUuid::createUuid().toString();
×
UNCOV
944
        itemModel->removeRows(0, itemModel->rowCount()); // don't use clear() here!
×
945
        currentItemCollection.clear();
×
946

947
        //ui->treeView->clearSelection(); ???
UNCOV
948
        switchEditMode(true, true);
×
949

950
        ui->listNameLineEdit->setText(q_("New Observation List"));
×
UNCOV
951
        ui->titleBar->setTitle(q_("Observing list creation mode"));
×
952
}
×
953
/*
954
 * Slot for editButton
955
*/
UNCOV
956
void ObsListDialog::editListButtonPressed()
×
957
{
958
        Q_ASSERT(!selectedOlud.isEmpty());
×
959

960
        if (!selectedOlud.isEmpty())
×
961
        {
962
                switchEditMode(true, false);
×
963

964
                ui->titleBar->setTitle(q_("Observing list editor mode"));
×
965
        }
966
        else
967
        {
UNCOV
968
                qCritical() << "ObsListDialog::editListButtonPressed(): selectedOlud is empty";
×
UNCOV
969
                messageBox(q_("Error"), q_("selectedOlud empty. This is a bug"));
×
970
        }
971
}
×
972

973
/*
974
 * Slot for button obsListExportListButton
975
 */
UNCOV
976
void ObsListDialog::exportListButtonPressed()
×
977
{
978
        static const QString filter = "Stellarium Single Observing List (*.sol);;Stellarium Observing List (*.ol)";
×
UNCOV
979
        const QString destinationDir=StelApp::getInstance().getSettings()->value("main/observinglists_dir", QDir::homePath()).toString();
×
980
        QString selectedFilter = "Stellarium Single Observing List (*.sol)";
×
981
        QString exportListJsonPath = QFileDialog::getSaveFileName(&StelMainView::getInstance(), q_("Export observing list as..."),
×
982
                                                              destinationDir + "/" + JSON_FILE_BASENAME + "_" + currentListName + ".sol", filter, &selectedFilter);
×
983

984
        if (exportListJsonPath.isEmpty()) // cancel pressed.
×
UNCOV
985
                return;
×
986

987
        QFile jsonFile(exportListJsonPath);
×
UNCOV
988
        if (!jsonFile.open(QIODevice::ReadWrite | QIODevice::Text))
×
989
        {
990
                qWarning() << "[ObservingList Creation/Edition] Error exporting observing list. "
×
UNCOV
991
                           << "File cannot be opened for reading and writing:"
×
992
                           << QDir::toNativeSeparators(exportListJsonPath);
×
993
                messageBox(q_("Error"), q_("Cannot export. See logfile for details."));
×
994
                return;
×
995
        }
996

UNCOV
997
        jsonFile.resize(0);
×
UNCOV
998
        QFileInfo fi(exportListJsonPath);
×
999
        if (fi.suffix()=="sol")
×
1000
        {
1001
                // Prepare a new json-able map
1002
                QVariantMap exportJsonMap={
1003
                        {KEY_DEFAULT_LIST_OLUD, ""}, // Do not set a default in this list!
1004
                        {KEY_SHORT_NAME, SHORT_NAME_VALUE},
UNCOV
1005
                        {KEY_VERSION, FILE_VERSION}};
×
1006

1007
                QVariantMap currentListMap={{selectedOlud, observingLists.value(selectedOlud).toMap()}};
×
1008
                //QVariantMap oneListMap={{KEY_OBSERVING_LISTS, currentListMap}};
1009
                //exportJsonMap.insert(KEY_OBSERVING_LISTS, oneListMap);
UNCOV
1010
                exportJsonMap.insert(KEY_OBSERVING_LISTS, currentListMap);
×
UNCOV
1011
                StelJsonParser::write(exportJsonMap, &jsonFile);
×
1012
        }
×
1013
        else
1014
        {
1015
                // just export complete map.
UNCOV
1016
                StelJsonParser::write(jsonMap, &jsonFile);
×
1017
        }
1018

UNCOV
1019
        jsonFile.flush();
×
UNCOV
1020
        jsonFile.close();
×
1021
}
×
1022

1023
/*
1024
 * Slot for button obsListImportListButton
1025
 */
UNCOV
1026
void ObsListDialog::importListButtonPressed()
×
1027
{
1028
        static const QString filter = "Stellarium Single Observing List (*.sol);;Stellarium Observing List (*.ol);;Stellarium Legacy JSON Observing List or Bookmarks (*.json)";
×
UNCOV
1029
        const QString destinationDir=StelApp::getInstance().getSettings()->value("main/observinglists_dir", QDir::homePath()).toString();
×
1030
        QString fileToImportJsonPath = QFileDialog::getOpenFileName(&StelMainView::getInstance(), q_("Import observing list"),
×
1031
                                                                    destinationDir,
1032
                                                                    filter);
×
UNCOV
1033
        if (fileToImportJsonPath.isEmpty()) // cancel pressed.
×
1034
                return;
×
1035

1036
        QVariantMap map;
×
UNCOV
1037
        QFile jsonFile(fileToImportJsonPath);
×
1038
        if (!jsonFile.open(QIODevice::ReadOnly))
×
1039
        {
1040
                qWarning() << "[ObservingList Import] cannot open"
×
UNCOV
1041
                           << QDir::toNativeSeparators(jsonFile.fileName());
×
1042
                messageBox(q_("Error"), q_("Cannot open selected file for import"));
×
1043
                return;
×
1044
        }
1045
        else
1046
        {
1047
                try {
UNCOV
1048
                        map = StelJsonParser::parse(jsonFile.readAll()).toMap();
×
UNCOV
1049
                        jsonFile.close();
×
1050

1051
                        if (map.contains(KEY_OBSERVING_LISTS))
×
1052
                        {
1053
                                // Case of observingList import: Import all lists from that file! A .sol only has one list but is else structured identically.
UNCOV
1054
                                const QVariantMap observingListMapToImport = map.value(KEY_OBSERVING_LISTS).toMap();
×
UNCOV
1055
                                if (observingListMapToImport.isEmpty())
×
1056
                                {
1057
                                        qWarning() << "[ObservingList Creation/Edition import] empty list:" << fileToImportJsonPath;
×
UNCOV
1058
                                        messageBox(q_("Error"), q_("Empty list."));
×
1059
                                        return;
×
1060
                                }
1061
                                else
1062
                                {
UNCOV
1063
                                        QVariantMap::const_iterator it;
×
UNCOV
1064
                                        for (it = observingListMapToImport.begin(); it != observingListMapToImport.end(); ++it) {
×
1065
                                                if (it.value().canConvert<QVariantMap>())
×
1066
                                                {
1067
                                                        // check here to avoid overwriting of existing lists
UNCOV
1068
                                                        bool overwrite=true;
×
UNCOV
1069
                                                        if (observingLists.contains(it.key())) // Same OLUD?
×
1070
                                                        {
1071
                                                                QVariantMap importedMap=it.value().toMap(); // This is a map of {{UUID, QMap},...}
×
UNCOV
1072
                                                                QString importedName=importedMap.value(KEY_NAME).toString();
×
1073
                                                                QString importedDate=importedMap.value(KEY_CREATION_DATE).toString();
×
1074
                                                                QString importedLastEditDate=importedMap.value(KEY_LAST_EDIT, importedMap.value(KEY_CREATION_DATE)).toString();
×
1075
                                                                qDebug() << "Imported Map named:" << importedName << "created" << importedDate << "changed" << importedLastEditDate << ":" << importedMap;
×
1076
                                                                QVariantMap existingMap=observingLists.value(it.key()).toMap();
×
1077
                                                                QString existingName=existingMap.value(KEY_NAME).toString();
×
1078
                                                                QString existingDate=existingMap.value(KEY_CREATION_DATE).toString();
×
1079
                                                                QString existingLastEdit=existingMap.value(KEY_LAST_EDIT, existingMap.value(KEY_CREATION_DATE)).toString();
×
1080
                                                                QString message=QString(q_("A list named '%1', created %2 and last modified %3 would overwrite your existing list '%4', dated %5 and last modified %6. Accept?")).arg(importedName, importedDate, importedLastEditDate, existingName, existingDate, existingLastEdit);
×
1081
                                                                overwrite=askConfirmation(message);
×
1082
                                                        }
×
1083
                                                        if (overwrite)
×
1084
                                                        {
1085
                                                                observingLists.insert(it.key(), it.value());
×
UNCOV
1086
                                                                selectedOlud=it.key();
×
1087
                                                        }
1088
                                                }
1089
                                        }
1090
                                }
UNCOV
1091
                        }
×
UNCOV
1092
                        else if (map.contains(KEY_BOOKMARKS))
×
1093
                        {
1094
                                // Case of legacy bookmarks import
UNCOV
1095
                                QVariantMap bookmarksListMap = map.value(KEY_BOOKMARKS).toMap();
×
UNCOV
1096
                                if (bookmarksListMap.isEmpty())
×
1097
                                {
1098
                                        qWarning() << "[ObservingList Creation/Edition import] the file is empty or doesn't contain legacy bookmarks.";
×
UNCOV
1099
                                        messageBox(q_("Error"), q_("The file is empty or doesn't contain legacy bookmarks."));
×
1100
                                        return;
×
1101
                                }
1102
                                else
1103
                                {
UNCOV
1104
                                        QHash<QString, ObsListDialog::observingListItem> bookmarksHash=loadBookmarksFile(jsonFile);
×
1105
                                        // Put them to the main list. Note that this may create another list named "bookmarks list", however, with a different OLUD than the existing.
1106
                                        selectedOlud=saveBookmarksHashInObservingLists(bookmarksHash);
×
UNCOV
1107
                                }
×
1108
                        }
×
1109
                        else
1110
                        {
UNCOV
1111
                                messageBox(q_("Error"), q_("File does not contain observing lists or legacy bookmarks"));
×
UNCOV
1112
                                return;
×
1113
                        }
1114

1115
                        // At this point we have added our lists to the observingLists map. Now update the jsonMap and store to file.
UNCOV
1116
                        QFile jsonFile(observingListJsonPath);
×
UNCOV
1117
                        if (!jsonFile.open(QIODevice::ReadWrite | QIODevice::Text)) {
×
1118
                                qWarning() << "[ObservingList] bookmarks list can not be saved. A file can not be open for reading and writing:"
×
1119
                                           << QDir::toNativeSeparators(observingListJsonPath);
×
1120
                                messageBox(q_("Error"), q_("Cannot open observingLists.json to write"));
×
1121
                                return;
×
1122
                        }
1123
                        // Update the jsonMap and store
UNCOV
1124
                        jsonMap.insert(KEY_OBSERVING_LISTS, observingLists);
×
UNCOV
1125
                        jsonFile.resize(0);
×
1126
                        StelJsonParser::write(jsonMap, &jsonFile);
×
1127
                        jsonFile.flush();
×
1128
                        jsonFile.close();
×
1129
                        tainted=false;
×
1130

1131
                        // Now we have stored to file, but the program is not aware of the new lists!
UNCOV
1132
                        loadListNames(selectedOlud); // also populate Combobox and make sure at least some defaultOlud exists.
×
UNCOV
1133
                        Q_ASSERT(selectedOlud.length()>0);
×
1134

1135
                        loadSelectedList();
×
UNCOV
1136
                } catch (std::runtime_error &e) {
×
1137
                        qWarning() << "[ObservingList Creation/Edition] File format is wrong! Error: " << e.what();
×
1138
                        messageBox(q_("Error"), q_("File format is wrong!"));
×
1139
                        return;
×
1140
                }
×
1141
        }
1142
}
×
1143

1144
/*
1145
 * Delete the currently selected list. There must be at least one list.
1146
*/
UNCOV
1147
void ObsListDialog::deleteListButtonPressed()
×
1148
{
1149
        if (observingLists.count()>1 && (selectedOlud!=defaultOlud))
×
1150
        {
1151
                if (!askConfirmation()) // place inside to avoid error message below.
×
UNCOV
1152
                        return;
×
1153

1154
                QFile jsonFile(observingListJsonPath);
×
UNCOV
1155
                if (!jsonFile.open(QIODevice::ReadWrite | QIODevice::Text)) {
×
1156
                        qWarning() << "[ObservingList] bookmarks list can not be saved. A file can not be open for reading and writing:"
×
1157
                                   << QDir::toNativeSeparators(observingListJsonPath);
×
1158
                        messageBox(q_("Error"), q_("Cannot open JSON output file. Will not delete."));
×
1159
                        return;
×
1160
                }
1161

UNCOV
1162
                observingLists.remove(selectedOlud);
×
UNCOV
1163
                currentItemCollection.clear();
×
1164

1165
                selectedOlud=defaultOlud;
×
1166
                // Update the jsonMap and store
1167
                jsonMap.insert(KEY_OBSERVING_LISTS, observingLists);
×
UNCOV
1168
                jsonFile.resize(0);
×
1169
                StelJsonParser::write(jsonMap, &jsonFile);
×
1170
                jsonFile.flush();
×
1171
                jsonFile.close();
×
1172
                tainted=false;
×
1173

1174
                // Clean up UI
UNCOV
1175
                clearHighlights();
×
UNCOV
1176
                loadListNames();
×
1177
                loadSelectedList();
×
1178
        }
×
1179
        else
1180
        {
UNCOV
1181
                qDebug() << "deleteButtonPressed: You cannot delete the default or the last list.";
×
UNCOV
1182
                messageBox(q_("Information"), q_("You cannot delete the default or the last list."));
×
1183
        }
1184
}
1185

1186
/*
1187
 * Slot for addObjectButton.
1188
 * Save selected object into the list of observed objects.
1189
 */
UNCOV
1190
void ObsListDialog::addObjectButtonPressed()
×
1191
{
1192
        const double JD = core->getJD();
×
UNCOV
1193
        const double fov = (ui->fovCheckBox->isChecked() ? GETSTELMODULE(StelMovementMgr)->getCurrentFov() : -1.0);
×
1194
        const QString Location = core->getCurrentLocation().serializeToLine(); // store completely
×
1195
        const QString landscapeID=GETSTELMODULE(LandscapeMgr)->getCurrentLandscapeID();
×
1196

1197
        const QList<StelObjectP> &selectedObject = objectMgr->getSelectedObject();
×
1198

1199
        if (!selectedObject.isEmpty())
×
1200
        {
1201
// TBD: this test should prevent adding duplicate entries, but fails. Maybe for V23.4!
1202
//                // No duplicate item in the same list
1203
//                bool is_already_in_list = false;
1204
//                QHash<QString, observingListItem>::iterator i;
1205
//                for (i = observingListItemCollection.begin(); i != observingListItemCollection.end(); i++)
1206
//                {
1207
//                        if ((i.value().name.compare(selectedObject[0]->getEnglishName()) == 0) &&
1208
//                                (ui->obsListJDCheckBox->isChecked()        && i.value().jd == JD) &&
1209
//                                (ui->obsListFovCheckBox->isChecked()       && i.value().fov == fov) &&
1210
//                                (ui->obsListLandscapeCheckBox->isChecked() && i.value().landscapeID == landscapeID) &&
1211
//                                (ui->obsListLocationCheckBox->isChecked()  && i.value().location == Location))
1212
//                        {
1213
//                                is_already_in_list = true;
1214
//                                break;
1215
//                        }
1216
//                }
1217
//
1218
//                if (!is_already_in_list)
1219
//                {
UNCOV
1220
                        observingListItem item;
×
1221

1222
                        const QString objectUUID = QUuid::createUuid().toString();
×
1223

1224
                        // Object name (designation) and object name I18n
UNCOV
1225
                        if (selectedObject[0]->getType() == "Nebula")
×
UNCOV
1226
                                item.designation = GETSTELMODULE(NebulaMgr)->getLatestSelectedDSODesignationWIC(); // Store most common catalog ID as of our catalog sequence, even if catalog is not active
×
1227
                        else
1228
                                item.designation = selectedObject[0]->getEnglishName();
×
UNCOV
1229
                        item.name = selectedObject[0]->getEnglishName();
×
1230
                        item.nameI18n = selectedObject[0]->getNameI18n();
×
1231
                        if(item.nameI18n.isEmpty())
×
1232
                                item.nameI18n = DASH;
×
1233
                        // Check if the object name is empty.
1234
                        if (item.designation.isEmpty())
×
1235
                        {
1236
                                item.designation = "Unnamed object";
×
UNCOV
1237
                                if (item.nameI18n.isEmpty()) {
×
1238
                                        item.nameI18n = q_("Unnamed object");
×
1239
                                }
1240
                        }
1241
                        // Type, Object Type
UNCOV
1242
                        item.objClass = selectedObject[0]->getType();
×
UNCOV
1243
                        item.objTypeI18n = selectedObject[0]->getObjectTypeI18n();
×
1244

1245
                        // Ra & Dec
UNCOV
1246
                        if (ui->coordinatesCheckBox->isChecked() || (item.objClass == "Planet" && getFlagUseJD()) || item.objClass == CUSTOM_OBJECT || item.designation.isEmpty()) {
×
1247
                                double ra, dec;
1248
                                StelUtils::rectToSphe(&ra, &dec, selectedObject[0]->getJ2000EquatorialPos(core));
×
UNCOV
1249
                                item.ra  = StelUtils::radToHmsStr(ra,  false).trimmed();
×
1250
                                item.dec = StelUtils::radToDmsStr(dec, false).trimmed();
×
1251
                        }
1252
                        item.isVisibleMarker=!item.designation.contains("marker", Qt::CaseInsensitive);
×
UNCOV
1253
                        item.magnitude = getMagnitude(selectedObject, core);
×
1254

1255
                        // Constellation
UNCOV
1256
                        const Vec3d posNow = selectedObject[0]->getEquinoxEquatorialPos(core);
×
UNCOV
1257
                        item.constellation = core->getIAUConstellation(posNow);
×
1258

1259
                        // Optional: JD, Location, landscape, fov
UNCOV
1260
                        if (getFlagUseJD())
×
UNCOV
1261
                                item.jd = JD;
×
1262
                        if (getFlagUseLocation())
×
1263
                                item.location = Location;
×
1264
                        if (getFlagUseLandscape())
×
1265
                                item.landscapeID = landscapeID;
×
1266
                        if (getFlagUseFov() && (fov > 1.e-6))
×
1267
                                item.fov = fov;
×
1268

1269
                        currentItemCollection.insert(objectUUID, item);
×
UNCOV
1270
                        tainted=true;
×
1271

1272
                        // Add object in row model
UNCOV
1273
                        StelLocation loc=StelLocation::createFromLine(Location);
×
UNCOV
1274
                        addModelRow(objectUUID,
×
1275
                                    item.designation,
1276
                                    item.nameI18n,
1277
                                    item.objTypeI18n,
1278
                                    item.ra,
1279
                                    item.dec,
1280
                                    item.magnitude,
1281
                                    item.constellation,
UNCOV
1282
                                    ui->jdCheckBox->isChecked() ? StelUtils::julianDayToISO8601String(JD + core->getUTCOffset(JD) / 24.).replace("T", " ") : "",
×
UNCOV
1283
                                    ui->locationCheckBox->isChecked() ? loc.name : "",
×
1284
                                    item.landscapeID);
1285
//                }
UNCOV
1286
        }
×
1287
        else
1288
                qWarning() << "Selected object is empty!";
×
UNCOV
1289
}
×
1290

1291
/*
1292
 * Slot for button obsListRemoveObjectButton
1293
 */
UNCOV
1294
void ObsListDialog::removeObjectButtonPressed()
×
1295
{
1296
        Q_ASSERT(isEditMode);
×
1297

1298
        int number = ui->treeView->currentIndex().row();
×
UNCOV
1299
        QString uuid = itemModel->index(number, ColumnUUID).data().toString();
×
1300
        itemModel->removeRow(number);
×
1301
        currentItemCollection.remove(uuid);
×
1302
        tainted=true;
×
1303
}
×
1304

1305
/*
1306
 * Slot for saveButton
1307
 */
UNCOV
1308
void ObsListDialog::saveButtonPressed()
×
1309
{
1310
        Q_ASSERT(isEditMode);
×
UNCOV
1311
        if (!isEditMode)
×
1312
        {
1313
                qCritical() << "CALLING ERROR: saveButtonPressed() while not in edit mode.";
×
UNCOV
1314
                return;
×
1315
        }
1316

1317
        // we have a valid selectedListOlud. In addition, the list must have a human-readable name.
UNCOV
1318
        QString listName = ui->listNameLineEdit->text().trimmed();
×
UNCOV
1319
        if (listName.length()==0)
×
1320
        {
1321
                messageBox(q_("Error"), q_("Empty name"));
×
UNCOV
1322
                return;
×
1323
        }
1324
        if (listNames.contains(listName) && isCreationMode)
×
1325
        {
1326
                messageBox(q_("Error"), q_("List name already exists"));
×
UNCOV
1327
                return;
×
1328
        }
1329

1330
        // Last chance to detect any change: Just list name changed?
UNCOV
1331
        if (currentListName!=listName)
×
UNCOV
1332
                tainted=true;
×
1333

1334
        if (!tainted)
×
UNCOV
1335
                return;
×
1336

1337
        //OK, we save this and keep it as current list.
UNCOV
1338
        currentListName=listName;
×
1339

1340
        QFile jsonFile(observingListJsonPath);
×
UNCOV
1341
        if (!jsonFile.open(QIODevice::ReadWrite | QIODevice::Text))
×
1342
        {
1343
                qWarning() << "[ObservingList Save] Error saving observing list. "
×
UNCOV
1344
                           << "File cannot be opened for reading and writing:"
×
1345
                           << QDir::toNativeSeparators(observingListJsonPath);
×
1346
                return;
×
1347
        }
1348

UNCOV
1349
        QVariantMap currentList=prepareCurrentList(currentItemCollection);
×
UNCOV
1350
        observingLists.insert(selectedOlud, currentList);
×
1351
        jsonMap.insert(KEY_OBSERVING_LISTS, observingLists);
×
1352

1353
        jsonFile.resize(0);
×
UNCOV
1354
        StelJsonParser::write(jsonMap, &jsonFile);
×
1355
        jsonFile.flush();
×
1356
        jsonFile.close();
×
1357

1358
        tainted=false;
×
UNCOV
1359
        switchEditMode(false, false); // Set GUI to normal mode
×
1360
        loadListNames(selectedOlud); // reload Combobox
×
1361
        loadSelectedList();
×
1362
}
×
1363

1364
/*
1365
 * Slot for cancelButton
1366
 */
UNCOV
1367
void ObsListDialog::cancelButtonPressed()
×
1368
{
1369
        Q_ASSERT(isEditMode);
×
UNCOV
1370
        if (!isEditMode)
×
1371
        {
1372
                qCritical() << "CALLING ERROR: cancelButtonPressed() while not in edit mode.";
×
UNCOV
1373
                return;
×
1374
        }
1375
        // Depending on creation or regular edit mode, delete current list and load default, or reload current list,
UNCOV
1376
        if (isCreationMode)
×
UNCOV
1377
                loadDefaultList();
×
1378
        else
1379
                loadSelectedList();
×
1380

1381
        // then close editing mode and set GUI to normal mode
UNCOV
1382
        switchEditMode(false, false);
×
1383
}
1384

UNCOV
1385
void ObsListDialog::switchEditMode(bool enableEditMode, bool newList)
×
1386
{
1387
                isEditMode=enableEditMode;
×
UNCOV
1388
                isCreationMode=newList;
×
1389
                // The Layout classes have no setVisible(bool), we must configure individual buttons! :-(
1390

UNCOV
1391
                ui->titleBar->setTitle(q_("Observing lists"));
×
1392
                //ui->horizontalLayoutCombo->setEnabled(!isEditMode);     // disable list selection
1393
                ui->obsListComboLabel->setVisible(!isEditMode);
×
UNCOV
1394
                ui->obsListComboBox->setVisible(!isEditMode);
×
1395

1396
                // horizontalLayoutLineEdit_1: labelListName, nameOfListLIneEdit
1397
                //ui->horizontalLayout_Name->setEnabled(isEditMode);  // enable list name editing
UNCOV
1398
                ui->listNameLabel->setVisible(isEditMode);
×
1399
                //ui->horizontalSpacer_listName->sizePolicy().setHeightForWidth(isEditMode);// ->setVisible(isEditMode);
1400
                //qDebug() << "Spacer geometry, policy:" << ui->horizontalSpacer_listName->geometry() << ui->horizontalSpacer_listName->sizePolicy();
UNCOV
1401
                ui->listNameLineEdit->setVisible(isEditMode);
×
UNCOV
1402
                ui->listNameLineEdit->setText(currentListName);
×
1403

1404
                ui->descriptionLineEdit->setEnabled(isEditMode);    // (activate description line)
×
1405

1406
                ui->creationDateLabel->setVisible(!isEditMode);         // Creation date:
×
UNCOV
1407
                ui->creationDateLineEdit->setVisible(!isEditMode);      //
×
1408
                ui->lastEditLabel->setVisible(!isEditMode);             // Last edit date:
×
1409
                ui->lastEditLineEdit->setVisible(!isEditMode);          //
×
1410

1411
                // line with optional store items
UNCOV
1412
                ui->alsoStoreLabel->setVisible(isEditMode);            // Also store
×
UNCOV
1413
                ui->coordinatesCheckBox->setVisible(isEditMode);// hide "Coordinates"
×
1414
                ui->alsoLoadLabel->setVisible(!isEditMode);  // Also load
×
1415

1416
                //ui->horizontalLayoutButtons->setEnabled(!isEditMode);   // Highlight/Clear/NewList/EditList/DeleteList/ExportList/ImportList
UNCOV
1417
                ui->highlightAllButton->setVisible(!isEditMode);
×
UNCOV
1418
                ui->clearHighlightButton->setVisible(!isEditMode);
×
1419
                ui->newListButton->setVisible(!isEditMode);
×
1420
                ui->editListButton->setVisible(!isEditMode);
×
1421
                ui->deleteListButton->setVisible(!isEditMode);
×
1422
                ui->exportListButton->setVisible(!isEditMode);
×
1423
                ui->importListButton->setVisible(!isEditMode);
×
1424

1425
                //ui->horizontalLayoutButtons_1->setEnabled(isEditMode); // Add/Remove/Export/Import
UNCOV
1426
                ui->addObjectButton->setVisible(isEditMode);
×
UNCOV
1427
                ui->removeObjectButton->setVisible(isEditMode);
×
1428
                ui->saveButton->setVisible(isEditMode);
×
1429
                ui->cancelButton->setVisible(isEditMode);
×
1430
}
×
1431

1432
/*
1433
 * Sort the treeView by the column name given in parameter
1434
*/
UNCOV
1435
void ObsListDialog::sortObsListTreeViewByColumnName(const QString &columnName)
×
1436
{
1437
        static const QMap<QString,int>map={
UNCOV
1438
                {SORTING_BY_NAME,          ColumnDesignation},
×
UNCOV
1439
                {SORTING_BY_NAMEI18N,      ColumnNameI18n},
×
1440
                {SORTING_BY_TYPE,          ColumnType},
×
1441
                {SORTING_BY_RA,            ColumnRa},
×
1442
                {SORTING_BY_DEC,           ColumnDec},
×
1443
                {SORTING_BY_MAGNITUDE,     ColumnMagnitude},
×
1444
                {SORTING_BY_CONSTELLATION, ColumnConstellation},
×
1445
                {SORTING_BY_DATE,          ColumnDate},
×
1446
                {SORTING_BY_LOCATION,      ColumnLocation},
×
1447
                {SORTING_BY_LANDSCAPE_ID,  ColumnLandscapeID}
×
1448
        };
×
1449
    ObsListDialogSortFilterProxyModel *proxyModel = new ObsListDialogSortFilterProxyModel;
×
1450
    proxyModel->setSourceModel(itemModel);
×
1451
    ui->treeView->setModel(proxyModel);
×
1452
    proxyModel->sort(map.value(columnName), Qt::AscendingOrder);
×
1453
}
×
1454

1455
void ObsListDialog::setFlagUseJD(bool b)
×
1456
{
1457
        QSettings* conf = StelApp::getInstance().getSettings();
×
UNCOV
1458
        flagUseJD=b;
×
1459
        conf->setValue("bookmarks/useJD", b);
×
1460
        emit flagUseJDChanged(b);
×
1461
}
×
1462
void ObsListDialog::setFlagUseLandscape(bool b)
×
1463
{
1464
        QSettings* conf = StelApp::getInstance().getSettings();
×
UNCOV
1465
        flagUseLandscape=b;
×
1466
        conf->setValue("bookmarks/useLandscape", b);
×
1467
        emit flagUseLandscapeChanged(b);
×
1468
}
×
1469
void ObsListDialog::setFlagUseLocation(bool b)
×
1470
{
1471
        QSettings* conf = StelApp::getInstance().getSettings();
×
UNCOV
1472
        flagUseLocation=b;
×
1473
        conf->setValue("bookmarks/useLocation", b);
×
1474
        emit flagUseLocationChanged(b);
×
1475
}
×
1476
void ObsListDialog::setFlagUseFov(bool b)
×
1477
{
1478
        QSettings* conf = StelApp::getInstance().getSettings();
×
UNCOV
1479
        flagUseFov=b;
×
1480
        conf->setValue("bookmarks/useFOV", b);
×
1481
        emit flagUseFovChanged(b);
×
1482
}
×
1483

1484
/*
1485
 * Prepare the currently displayed/edited list for storage
1486
 * Returns QVariantList with keys={creation date, last edit, description, name, objects, sorting}
1487
 */
UNCOV
1488
QVariantMap ObsListDialog::prepareCurrentList(QHash<QString, observingListItem> &itemHash)
×
1489
{
1490
        // Edit date
UNCOV
1491
        const double JD = StelUtils::getJDFromSystem();
×
UNCOV
1492
        const QString lastEditDate = StelUtils::julianDayToISO8601String(JD + core->getUTCOffset(JD) / 24.).replace("T", " ");
×
1493
        QVariantMap currentList = {
1494
                // Name, description, current date for the list, current sorting
UNCOV
1495
                {KEY_NAME,          currentListName},
×
UNCOV
1496
                {KEY_DESCRIPTION,   ui->descriptionLineEdit->text()},
×
1497
                {KEY_SORTING,       sorting},
×
1498
                {KEY_CREATION_DATE, ui->creationDateLineEdit->text()},
×
1499
                {KEY_LAST_EDIT,     lastEditDate }
1500
        };
×
1501

1502
        // List of objects
UNCOV
1503
        QVariantList listOfObjects;
×
UNCOV
1504
        QHashIterator<QString, observingListItem> i(itemHash);
×
1505
        while (i.hasNext())
×
1506
        {
1507
                i.next();
×
UNCOV
1508
                observingListItem item = i.value();
×
1509
                listOfObjects.push_back(item.toVariantMap());
×
1510
        }
×
1511
        currentList.insert(KEY_OBJECTS, listOfObjects);
×
1512

1513
        return currentList;
×
UNCOV
1514
}
×
1515

1516
/*
1517
 * Slot for obsListCreationEditionTreeView header
1518
 */
UNCOV
1519
void ObsListDialog::headerClicked(int index)
×
1520
{
1521
        static const QMap<int,QString> map={
UNCOV
1522
                {ColumnDesignation,   SORTING_BY_NAME},
×
UNCOV
1523
                {ColumnNameI18n,      SORTING_BY_NAMEI18N},
×
1524
                {ColumnType,          SORTING_BY_TYPE},
×
1525
                {ColumnRa,            SORTING_BY_RA},
×
1526
                {ColumnDec,           SORTING_BY_DEC},
×
1527
                {ColumnMagnitude,     SORTING_BY_MAGNITUDE},
×
1528
                {ColumnConstellation, SORTING_BY_CONSTELLATION},
×
1529
                {ColumnDate,          SORTING_BY_DATE},
×
1530
                {ColumnLocation,      SORTING_BY_LOCATION},
×
1531
                {ColumnLandscapeID,   SORTING_BY_LANDSCAPE_ID}};
×
1532
        sorting=map.value(index, "");
×
1533
        //qDebug() << "Sorting = " << sorting;
1534
        sortObsListTreeViewByColumnName(sorting);
×
UNCOV
1535
}
×
1536

1537
// Get the magnitude from selected object (or a dash if unavailable)
UNCOV
1538
QString ObsListDialog::getMagnitude(const QList<StelObjectP> &selectedObject, StelCore *core)
×
1539
{
1540
        if (!core)
×
UNCOV
1541
                return DASH;
×
1542

1543
        QString objectMagnitudeStr(DASH);
×
UNCOV
1544
        const float objectMagnitude = selectedObject[0]->getVMagnitude(core);
×
1545
        if (objectMagnitude > 98.f)
×
1546
        {
1547
                if (QString::compare(selectedObject[0]->getType(), "Nebula", Qt::CaseSensitive) == 0)
×
1548
                {
1549
                        auto &r_nebula = dynamic_cast<Nebula &>(*selectedObject[0]);
×
UNCOV
1550
                        const float mB = r_nebula.getBMagnitude(core);
×
1551
                        if (mB < 98.f)
×
1552
                                objectMagnitudeStr = QString::number(mB);
×
1553
                }
1554
        }
1555
        else
UNCOV
1556
                objectMagnitudeStr = QString::number(objectMagnitude, 'f', 2);
×
1557

1558
        return objectMagnitudeStr;
×
UNCOV
1559
}
×
1560

1561
void ObsListDialog::defaultClicked(bool b)
×
1562
{
1563
        defaultOlud = (b ? selectedOlud : "");
×
UNCOV
1564
        jsonMap.insert(KEY_DEFAULT_LIST_OLUD, defaultOlud);
×
1565
        tainted=true;
×
1566
}
×
1567

1568
const QString ObsListDialog::JSON_FILE_NAME     = QStringLiteral("observingList.json");
1569
const QString ObsListDialog::JSON_FILE_BASENAME = QStringLiteral("observingList");
1570
const QString ObsListDialog::FILE_VERSION       = QStringLiteral("2.1");
1571

1572
const QString ObsListDialog::JSON_BOOKMARKS_FILE_NAME   = QStringLiteral("bookmarks.json");
1573
const QString ObsListDialog::BOOKMARKS_LIST_NAME        = QStringLiteral("bookmarks list");
1574
const QString ObsListDialog::BOOKMARKS_LIST_DESCRIPTION = QStringLiteral("Bookmarks of previous Stellarium version.");
1575
const QString ObsListDialog::SHORT_NAME_VALUE           = QStringLiteral("Observing list for Stellarium");
1576

1577
const QString ObsListDialog::KEY_DEFAULT_LIST_OLUD = QStringLiteral("defaultListOlud");
1578
const QString ObsListDialog::KEY_OBSERVING_LISTS   = QStringLiteral("observingLists");
1579
const QString ObsListDialog::KEY_CREATION_DATE     = QStringLiteral("creation date");
1580
const QString ObsListDialog::KEY_LAST_EDIT         = QStringLiteral("last edit");
1581
const QString ObsListDialog::KEY_BOOKMARKS         = QStringLiteral("bookmarks");
1582
const QString ObsListDialog::KEY_NAME              = QStringLiteral("name");
1583
const QString ObsListDialog::KEY_NAME_I18N         = QStringLiteral("nameI18n");
1584
const QString ObsListDialog::KEY_JD                = QStringLiteral("jd");
1585
const QString ObsListDialog::KEY_RA                = QStringLiteral("ra");
1586
const QString ObsListDialog::KEY_DEC               = QStringLiteral("dec");
1587
const QString ObsListDialog::KEY_FOV               = QStringLiteral("fov");
1588
const QString ObsListDialog::KEY_DESCRIPTION       = QStringLiteral("description");
1589
const QString ObsListDialog::KEY_LANDSCAPE_ID      = QStringLiteral("landscapeID");
1590
const QString ObsListDialog::KEY_OBJECTS           = QStringLiteral("objects");
1591
const QString ObsListDialog::KEY_OBJECTS_TYPE      = QStringLiteral("objtype");
1592
const QString ObsListDialog::KEY_TYPE              = QStringLiteral("type");
1593
const QString ObsListDialog::KEY_DESIGNATION       = QStringLiteral("designation");
1594
const QString ObsListDialog::KEY_SORTING           = QStringLiteral("sorting");
1595
const QString ObsListDialog::KEY_LOCATION          = QStringLiteral("location");
1596
const QString ObsListDialog::KEY_MAGNITUDE         = QStringLiteral("magnitude");
1597
const QString ObsListDialog::KEY_CONSTELLATION     = QStringLiteral("constellation");
1598
const QString ObsListDialog::KEY_VERSION           = QStringLiteral("version");
1599
const QString ObsListDialog::KEY_SHORT_NAME        = QStringLiteral("shortName");
1600
const QString ObsListDialog::KEY_IS_VISIBLE_MARKER = QStringLiteral("isVisibleMarker");
1601

1602
const QString ObsListDialog::SORTING_BY_NAME          = QStringLiteral("name");
1603
const QString ObsListDialog::SORTING_BY_NAMEI18N      = QStringLiteral("nameI18n");
1604
const QString ObsListDialog::SORTING_BY_TYPE          = QStringLiteral("type");
1605
const QString ObsListDialog::SORTING_BY_RA            = QStringLiteral("right ascension");
1606
const QString ObsListDialog::SORTING_BY_DEC           = QStringLiteral("declination");
1607
const QString ObsListDialog::SORTING_BY_MAGNITUDE     = QStringLiteral("magnitude");
1608
const QString ObsListDialog::SORTING_BY_CONSTELLATION = QStringLiteral("constellation");
1609
const QString ObsListDialog::SORTING_BY_DATE          = QStringLiteral("date");
1610
const QString ObsListDialog::SORTING_BY_LOCATION      = QStringLiteral("location");
1611
const QString ObsListDialog::SORTING_BY_LANDSCAPE_ID  = QStringLiteral("landscapeID");
1612

1613
const QString ObsListDialog::CUSTOM_OBJECT = QStringLiteral("CustomObject");
1614

1615
const QString ObsListDialog::DASH = QString(QChar(0x2014));
1616

UNCOV
1617
bool ObsListDialogSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
×
1618
{
1619
    if (sortColumn() == ObsListDialog::ColumnRa)
×
1620
    {
1621
        QString raLeft = sourceModel()->data(left).toString();
×
UNCOV
1622
        QString raRight = sourceModel()->data(right).toString();
×
1623
        return StelUtils::getDecAngle(raLeft) < StelUtils::getDecAngle(raRight);
×
1624
    }
×
1625
    if (sortColumn() == ObsListDialog::ColumnDec)
×
1626
    {
1627
        QString decLeft = sourceModel()->data(left).toString();
×
UNCOV
1628
        QString decRight = sourceModel()->data(right).toString();
×
1629
        return StelUtils::getDecAngle(decLeft) < StelUtils::getDecAngle(decRight);
×
1630
    }
×
1631
    if (sortColumn() == ObsListDialog::ColumnMagnitude)
×
1632
    {
1633
        QString magLeft = sourceModel()->data(left).toString();
×
UNCOV
1634
        QString magRight = sourceModel()->data(right).toString();
×
1635
        return magLeft.toDouble() < magRight.toDouble();
×
1636
    }
×
1637
    return QSortFilterProxyModel::lessThan(left, right);
×
1638
}
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