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

Stellarium / stellarium / 3996069357

pending completion
3996069357

push

github

Ruslan Kabatsayev
Shorten some lines

5 of 5 new or added lines in 1 file covered. (100.0%)

14663 of 124076 relevant lines covered (11.82%)

22035.13 hits per line

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

0.0
/src/gui/SearchDialog.cpp
1
/*
2
 * Stellarium
3
 * Copyright (C) 2008 Guillaume Chereau
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (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
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335, USA.
18
*/
19

20
#include "Dialog.hpp"
21
#include "SearchDialog.hpp"
22
#include "ui_searchDialogGui.h"
23
#include "StelApp.hpp"
24
#include "StelCore.hpp"
25
#include "StelModuleMgr.hpp"
26
#include "StelMovementMgr.hpp"
27
#include "StelLocaleMgr.hpp"
28
#include "StelTranslator.hpp"
29
#include "Planet.hpp"
30
#include "SpecialMarkersMgr.hpp"
31
#include "CustomObjectMgr.hpp"
32
#include "SolarSystem.hpp"
33
#include "NomenclatureMgr.hpp"
34

35
#include "StelObjectMgr.hpp"
36
#include "StelGui.hpp"
37
#include "StelUtils.hpp"
38

39
#include "StelFileMgr.hpp"
40
#include "StelJsonParser.hpp"
41

42
#include <QDebug>
43
#include <QFrame>
44
#include <QLabel>
45
#include <QPushButton>
46
#include <QSettings>
47
#include <QString>
48
#include <QStringList>
49
#include <QtAlgorithms>
50
#include <QTextEdit>
51
#include <QLineEdit>
52
#include <QComboBox>
53
#include <QMenu>
54
#include <QMetaEnum>
55
#include <QClipboard>
56
#include <QSortFilterProxyModel>
57
#include <QStringListModel>
58
#include <QFileDialog>
59
#include <QDir>
60
#include <QSet>
61
#include <QDialog>
62
#include <QAbstractItemModel>
63

64
#include "SimbadSearcher.hpp"
65

66
// Start of members for class CompletionListModel
67
CompletionListModel::CompletionListModel(QObject* parent):
×
68
        QStringListModel(parent),
69
        selectedIdx(0)
×
70
{
71
}
×
72

73
CompletionListModel::CompletionListModel(const QStringList &string, QObject* parent):
×
74
        QStringListModel(string, parent),
75
        selectedIdx(0)
×
76
{
77
}
×
78

79
CompletionListModel::~CompletionListModel()
×
80
{
81
}
×
82

83
void CompletionListModel::setValues(const QStringList& v, const QStringList& rv)
×
84
{
85
        values=v;
×
86
        recentValues=rv;
×
87
        updateText();
×
88
}
×
89

90
void CompletionListModel::appendRecentValues(const QStringList& v)
×
91
{
92
        recentValues+=v;
×
93
}
×
94

95
void CompletionListModel::appendValues(const QStringList& v)
×
96
{
97
        values+=v;
×
98
        updateText();
×
99
}
×
100

101
void CompletionListModel::clearValues()
×
102
{
103
        // Default: Show recent values
104
        values.clear();
×
105
        values = recentValues;
×
106
        selectedIdx=0;
×
107
        updateText();
×
108
}
×
109

110
QString CompletionListModel::getSelected() const
×
111
{
112
        if (values.isEmpty())
×
113
                return QString();
×
114
        return values.at(selectedIdx);
×
115
}
116

117
void CompletionListModel::selectNext()
×
118
{
119
        ++selectedIdx;
×
120
        if (selectedIdx>=values.size())
×
121
                selectedIdx=0;
×
122
        updateText();
×
123
}
×
124

125
void CompletionListModel::selectPrevious()
×
126
{
127
        --selectedIdx;
×
128
        if (selectedIdx<0)
×
129
                selectedIdx = values.size()-1;
×
130
        updateText();
×
131
}
×
132

133
void CompletionListModel::selectFirst()
×
134
{
135
        selectedIdx=0;
×
136
        updateText();
×
137
}
×
138

139
void CompletionListModel::updateText()
×
140
{
141
        this->setStringList(values);
×
142
}
×
143

144
QVariant CompletionListModel::data(const QModelIndex &index, int role) const
×
145
{
146
        if (!index.isValid())
×
147
            return QVariant();
×
148

149
        // Bold recent objects
150
        if(role == Qt::FontRole)
×
151
        {
152
            QFont font;
×
153
            bool toBold = recentValues.contains(index.data(Qt::DisplayRole).toString()) ?
×
154
                                    true : false;
155
            font.setBold(toBold);
×
156
            return font;
×
157
        }
×
158

159
        return QStringListModel::data(index, role);
×
160
}
161

162
// Start of members for class SearchDialog
163

164
const char* SearchDialog::DEF_SIMBAD_URL = "https://simbad.u-strasbg.fr/";
165
SearchDialog::SearchDialogStaticData SearchDialog::staticData;
166
QString SearchDialog::extSearchText = "";
167

168
SearchDialog::SearchDialog(QObject* parent)
×
169
        : StelDialog("Search", parent)
170
        , simbadReply(nullptr)
×
171
        , listModel(nullptr)
×
172
        , proxyModel(nullptr)
×
173
        , flagHasSelectedText(false)
×
174
        , shiftPressed(false)
×
175
{
176
        setObjectName("SearchDialog");
×
177
        ui = new Ui_searchDialogForm;
×
178
        simbadSearcher = new SimbadSearcher(this);
×
179
        objectMgr = GETSTELMODULE(StelObjectMgr);
×
180
        Q_ASSERT(objectMgr);
×
181

182
        StelApp::getInstance().getStelPropertyManager()->registerObject(this);
×
183
        conf = StelApp::getInstance().getSettings();
×
184
        enableSimbadSearch(conf->value("search/flag_search_online", true).toBool());
×
185
        useStartOfWords = conf->value("search/flag_start_words", false).toBool();
×
186
        useLockPosition = conf->value("search/flag_lock_position", true).toBool();
×
187
        useFOVCenterMarker = conf->value("search/flag_fov_center_marker", true).toBool();
×
188
        fovCenterMarkerState = GETSTELMODULE(SpecialMarkersMgr)->getFlagFOVCenterMarker();
×
189
        simbadServerUrl = conf->value("search/simbad_server_url", DEF_SIMBAD_URL).toString();
×
190
        setCurrentCoordinateSystemKey(conf->value("search/coordinate_system", "equatorialJ2000").toString());        
×
191

192
        setSimbadQueryDist( conf->value("search/simbad_query_dist",  30).toInt());
×
193
        setSimbadQueryCount(conf->value("search/simbad_query_count",  3).toInt());
×
194
        setSimbadGetsIds(   conf->value("search/simbad_query_IDs",        true ).toBool());
×
195
        setSimbadGetsSpec(  conf->value("search/simbad_query_spec",       false).toBool());
×
196
        setSimbadGetsMorpho(conf->value("search/simbad_query_morpho",     false).toBool());
×
197
        setSimbadGetsTypes( conf->value("search/simbad_query_types",      false).toBool());
×
198
        setSimbadGetsDims(  conf->value("search/simbad_query_dimensions", false).toBool());
×
199

200
        // Init CompletionListModel
201
        searchListModel = new CompletionListModel();
×
202

203
        // Find recent object search data file
204
        recentObjectSearchesJsonPath = StelFileMgr::findFile("data", static_cast<StelFileMgr::Flags>(StelFileMgr::Directory | StelFileMgr::Writable)) + "/recentObjectSearches.json";
×
205
}
×
206

207
SearchDialog::~SearchDialog()
×
208
{
209
        delete ui;
×
210
        if (simbadReply)
×
211
        {
212
                simbadReply->deleteLater();
×
213
                simbadReply = nullptr;
×
214
        }
215
}
×
216

217
void SearchDialog::retranslate()
×
218
{
219
        if (dialog)
×
220
        {
221
                QString text(ui->lineEditSearchSkyObject->text());
×
222
                ui->retranslateUi(dialog);
×
223
                ui->lineEditSearchSkyObject->setText(text);
×
224
                populateSimbadServerList();
×
225
                populateCoordinateSystemsList();
×
226
                populateCoordinateAxis();
×
227
                populateRecentSearch();
×
228
                updateListTab();
×
229
        }
×
230
}
×
231

232
void SearchDialog::setCurrentCoordinateSystemKey(QString key)
×
233
{
234
        const QMetaEnum& en = SearchDialog::metaObject()->enumerator(SearchDialog::metaObject()->indexOfEnumerator("CoordinateSystem"));
×
235
        CoordinateSystem coordSystem = static_cast<CoordinateSystem>(en.keyToValue(key.toLatin1().data()));
×
236
        if (coordSystem<0)
×
237
        {
238
                qWarning() << "[Search Tool] Unknown coordinate system: " << key << "setting \"equatorialJ2000\" instead";
×
239
                coordSystem = equatorialJ2000;
×
240
        }
241
        setCurrentCoordinateSystem(coordSystem);
×
242
}
×
243

244
QString SearchDialog::getCurrentCoordinateSystemKey() const
×
245
{
246
        return metaObject()->enumerator(metaObject()->indexOfEnumerator("CoordinateSystem")).key(currentCoordinateSystem);
×
247
}
248

249
void SearchDialog::populateCoordinateSystemsList()
×
250
{
251
        Q_ASSERT(ui->coordinateSystemComboBox);
×
252

253
        QComboBox* csys = ui->coordinateSystemComboBox;
×
254

255
        //Save the current selection to be restored later
256
        csys->blockSignals(true);
×
257
        int index = csys->currentIndex();
×
258
        QVariant selectedSystemId = csys->itemData(index);
×
259
        csys->clear();
×
260
        //For each coordinate system, display the localized name and store the key as user
261
        //data. Unfortunately, there's no other way to do this than with a cycle.
262
        csys->addItem(qc_("Equatorial (J2000.0)", "coordinate system"), "equatorialJ2000");
×
263
        csys->addItem(qc_("Equatorial", "coordinate system"), "equatorial");
×
264
        csys->addItem(qc_("Horizontal", "coordinate system"), "horizontal");
×
265
        csys->addItem(qc_("Galactic", "coordinate system"), "galactic");
×
266
        csys->addItem(qc_("Supergalactic", "coordinate system"), "supergalactic");
×
267
        csys->addItem(qc_("Ecliptic", "coordinate system"), "ecliptic");
×
268
        csys->addItem(qc_("Ecliptic (J2000.0)", "coordinate system"), "eclipticJ2000");
×
269

270
        //Restore the selection
271
        index = csys->findData(selectedSystemId, Qt::UserRole, Qt::MatchCaseSensitive);
×
272
        csys->setCurrentIndex(index);
×
273
        csys->blockSignals(false);
×
274
}
×
275

276
void SearchDialog::populateCoordinateAxis()
×
277
{
278
        bool withDecimalDegree = StelApp::getInstance().getFlagShowDecimalDegrees();
×
279
        bool xnormal = true;
×
280

281
        ui->AxisXSpinBox->setDecimals(2);
×
282
        ui->AxisYSpinBox->setDecimals(2);
×
283

284
        // Allow rotating through longitudinal coordinates, but stop at poles.
285
        ui->AxisXSpinBox->setMinimum(  0., true);
×
286
        ui->AxisXSpinBox->setMaximum(360., true);
×
287
        ui->AxisXSpinBox->setWrapping(true);
×
288
        ui->AxisYSpinBox->setMinimum(-90., true);
×
289
        ui->AxisYSpinBox->setMaximum( 90., true);
×
290
        ui->AxisYSpinBox->setWrapping(false);
×
291

292
        switch (getCurrentCoordinateSystem()) {                
×
293
                case equatorialJ2000:
×
294
                case equatorial:
295
                {
296
                        ui->AxisXLabel->setText(q_("Right ascension"));
×
297
                        ui->AxisXSpinBox->setDisplayFormat(AngleSpinBox::HMSLetters);
×
298
                        ui->AxisXSpinBox->setPrefixType(AngleSpinBox::Normal);
×
299
                        ui->AxisYLabel->setText(q_("Declination"));
×
300
                        ui->AxisYSpinBox->setDisplayFormat(AngleSpinBox::DMSSymbols);
×
301
                        ui->AxisYSpinBox->setPrefixType(AngleSpinBox::NormalPlus);
×
302
                        xnormal = true;
×
303
                        break;
×
304
                }
305
                case horizontal:
×
306
                {
307
                        ui->AxisXLabel->setText(q_("Azimuth"));
×
308
                        ui->AxisXSpinBox->setDisplayFormat(AngleSpinBox::DMSSymbolsUnsigned);
×
309
                        ui->AxisXSpinBox->setPrefixType(AngleSpinBox::NormalPlus);
×
310
                        ui->AxisYLabel->setText(q_("Altitude"));
×
311
                        ui->AxisYSpinBox->setDisplayFormat(AngleSpinBox::DMSSymbols);
×
312
                        ui->AxisYSpinBox->setPrefixType(AngleSpinBox::NormalPlus);
×
313
                        xnormal = false;
×
314
                        break;
×
315
                }
316
                case ecliptic:
×
317
                case eclipticJ2000:
318
                case galactic:
319
                case supergalactic:
320
                {
321
                        ui->AxisXLabel->setText(q_("Longitude"));
×
322
                        ui->AxisXSpinBox->setDisplayFormat(AngleSpinBox::DMSSymbolsUnsigned);
×
323
                        ui->AxisXSpinBox->setPrefixType(AngleSpinBox::NormalPlus);
×
324
                        ui->AxisYLabel->setText(q_("Latitude"));
×
325
                        ui->AxisYSpinBox->setDisplayFormat(AngleSpinBox::DMSSymbols);
×
326
                        ui->AxisYSpinBox->setPrefixType(AngleSpinBox::NormalPlus);
×
327
                        xnormal = false;
×
328
                        break;
×
329
                }
330
        }
331

332
        if (withDecimalDegree)
×
333
        {
334
                ui->AxisXSpinBox->setDecimals(5);
×
335
                ui->AxisYSpinBox->setDecimals(5);
×
336
                ui->AxisXSpinBox->setDisplayFormat(AngleSpinBox::DecimalDeg);
×
337
                ui->AxisYSpinBox->setDisplayFormat(AngleSpinBox::DecimalDeg);
×
338
                ui->AxisXSpinBox->setPrefixType(AngleSpinBox::NormalPlus);
×
339
        }
340
        else
341
        {
342
                if (xnormal)
×
343
                        ui->AxisXSpinBox->setPrefixType(AngleSpinBox::Normal);
×
344
        }
345
}
×
346

347
void SearchDialog::setCoordinateSystem(int csID)
×
348
{
349
        QString currentCoordinateSystemID = ui->coordinateSystemComboBox->itemData(csID).toString();
×
350
        setCurrentCoordinateSystemKey(currentCoordinateSystemID);
×
351
        populateCoordinateAxis();
×
352
        ui->AxisXSpinBox->setRadians(0.);
×
353
        ui->AxisYSpinBox->setRadians(0.);
×
354
        conf->setValue("search/coordinate_system", currentCoordinateSystemID);
×
355
}
×
356

357
// Initialize the dialog widgets and connect the signals/slots
358
void SearchDialog::createDialogContent()
×
359
{
360
        ui->setupUi(dialog);
×
361
        connect(&StelApp::getInstance(), SIGNAL(languageChanged()), this, SLOT(retranslate()));
×
362
        connect(&StelApp::getInstance(), SIGNAL(flagShowDecimalDegreesChanged(bool)), this, SLOT(populateCoordinateAxis()));
×
363
        connect(ui->closeStelWindow, SIGNAL(clicked()), this, SLOT(close()));
×
364
        connect(ui->TitleBar, SIGNAL(movedTo(QPoint)), this, SLOT(handleMovedTo(QPoint)));
×
365
        connect(ui->lineEditSearchSkyObject, SIGNAL(textChanged(const QString&)), this, SLOT(onSearchTextChanged(const QString&)));
×
366
        connect(ui->simbadCooQueryButton, SIGNAL(clicked()), this, SLOT(lookupCoordinates()));
×
367
        connect(GETSTELMODULE(StelObjectMgr), SIGNAL(selectedObjectChanged(StelModule::StelModuleSelectAction)), this, SLOT(clearSimbadText(StelModule::StelModuleSelectAction)));
×
368
        connect(ui->pushButtonGotoSearchSkyObject, SIGNAL(clicked()), this, SLOT(gotoObject()));
×
369
        onSearchTextChanged(ui->lineEditSearchSkyObject->text());
×
370
        connect(ui->lineEditSearchSkyObject, SIGNAL(returnPressed()), this, SLOT(gotoObject()));
×
371
        connect(ui->lineEditSearchSkyObject, SIGNAL(selectionChanged()), this, SLOT(setHasSelectedFlag()));
×
372
        connect(ui->lineEditSearchSkyObject, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint)));
×
373

374
        ui->lineEditSearchSkyObject->installEventFilter(this);        
×
375
        QSize bs = QSize(24, 24);
×
376
        ui->recentSearchClearDataPushButton->setFixedSize(bs);
×
377
        ui->goPushButton->setFixedSize(bs);
×
378
        ui->pushButtonGotoSearchSkyObject->setFixedSize(QSize(40, 30));
×
379

380
        // Kinetic scrolling
381
        kineticScrollingList << ui->objectsListView;
×
382
        StelGui* gui= dynamic_cast<StelGui*>(StelApp::getInstance().getGui());
×
383
        if (gui)
×
384
        {
385
                enableKineticScrolling(gui->getFlagUseKineticScrolling());
×
386
                connect(gui, SIGNAL(flagUseKineticScrollingChanged(bool)), this, SLOT(enableKineticScrolling(bool)));
×
387
        }
388

389
        populateCoordinateSystemsList();
×
390
        populateCoordinateAxis();
×
391
        int idx = ui->coordinateSystemComboBox->findData(getCurrentCoordinateSystemKey(), Qt::UserRole, Qt::MatchCaseSensitive);
×
392
        if (idx==-1) // Use equatorialJ2000 as default
×
393
                idx = ui->coordinateSystemComboBox->findData(QVariant("equatorialJ2000"), Qt::UserRole, Qt::MatchCaseSensitive);
×
394
        ui->coordinateSystemComboBox->setCurrentIndex(idx);
×
395
        connect(ui->coordinateSystemComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setCoordinateSystem(int)));
×
396
        connect(ui->AxisXSpinBox, SIGNAL(valueChanged()), this, SLOT(manualPositionChanged()));
×
397
        connect(ui->AxisYSpinBox, SIGNAL(valueChanged()), this, SLOT(manualPositionChanged()));
×
398
        connect(ui->goPushButton, SIGNAL(clicked(bool)), this, SLOT(manualPositionChanged()));
×
399
        
400
        connect(ui->alphaPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
401
        connect(ui->betaPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
402
        connect(ui->gammaPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
403
        connect(ui->deltaPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
404
        connect(ui->epsilonPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
405
        connect(ui->zetaPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
406
        connect(ui->etaPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
407
        connect(ui->thetaPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
408
        connect(ui->iotaPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
409
        connect(ui->kappaPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
410
        connect(ui->lambdaPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
411
        connect(ui->muPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
412
        connect(ui->nuPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
413
        connect(ui->xiPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
414
        connect(ui->omicronPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
415
        connect(ui->piPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
416
        connect(ui->rhoPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
417
        connect(ui->sigmaPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
418
        connect(ui->tauPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
419
        connect(ui->upsilonPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
420
        connect(ui->phiPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
421
        connect(ui->chiPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
422
        connect(ui->psiPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
423
        connect(ui->omegaPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
424

425
        connectBoolProperty(ui->simbadGroupBox, "SearchDialog.useSimbad");        
×
426
        connectIntProperty(ui->searchRadiusSpinBox,    "SearchDialog.simbadDist");
×
427
        connectIntProperty(ui->resultsSpinBox,         "SearchDialog.simbadCount");
×
428
        connectBoolProperty(ui->allIDsCheckBox,        "SearchDialog.simbadGetIds");
×
429
        connectBoolProperty(ui->spectralClassCheckBox, "SearchDialog.simbadGetSpec");
×
430
        connectBoolProperty(ui->morphoCheckBox,        "SearchDialog.simbadGetMorpho");
×
431
        connectBoolProperty(ui->typesCheckBox,         "SearchDialog.simbadGetTypes");
×
432
        connectBoolProperty(ui->dimsCheckBox,          "SearchDialog.simbadGetDims");
×
433

434
        populateSimbadServerList();
×
435
        idx = ui->serverListComboBox->findData(simbadServerUrl, Qt::UserRole, Qt::MatchCaseSensitive);
×
436
        if (idx==-1) // Use University of Strasbourg as default
×
437
                idx = ui->serverListComboBox->findData(QVariant(DEF_SIMBAD_URL), Qt::UserRole, Qt::MatchCaseSensitive);
×
438
        ui->serverListComboBox->setCurrentIndex(idx);
×
439
        connect(ui->serverListComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(selectSimbadServer(int)));
×
440

441
        connect(ui->checkBoxUseStartOfWords, SIGNAL(clicked(bool)), this, SLOT(enableStartOfWordsAutofill(bool)));
×
442
        ui->checkBoxUseStartOfWords->setChecked(useStartOfWords);
×
443

444
        connect(ui->checkBoxFOVCenterMarker, SIGNAL(clicked(bool)), this, SLOT(enableFOVCenterMarker(bool)));
×
445
        ui->checkBoxFOVCenterMarker->setChecked(useFOVCenterMarker);
×
446

447
        connect(ui->checkBoxLockPosition, SIGNAL(clicked(bool)), this, SLOT(enableLockPosition(bool)));
×
448
        ui->checkBoxLockPosition->setChecked(useLockPosition);
×
449

450
        // list views initialization
451
        listModel = new QStringListModel(this);
×
452
        proxyModel = new QSortFilterProxyModel(ui->objectsListView);
×
453
        proxyModel->setSourceModel(listModel);
×
454
        proxyModel->sort(0, Qt::AscendingOrder);
×
455
        proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
×
456
        ui->objectsListView->setModel(proxyModel);
×
457

458
        connect(ui->objectTypeComboBox, SIGNAL(activated(int)), this, SLOT(updateListView(int)));
×
459
        connect(ui->searchInListLineEdit, SIGNAL(textChanged(const QString&)), proxyModel, SLOT(setFilterWildcard(const QString&)));
×
460
        connect(ui->searchInEnglishCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateListTab()));
×
461
        QAction *clearAction = ui->searchInListLineEdit->addAction(QIcon(":/graphicGui/uieBackspaceInputButton.png"), QLineEdit::ActionPosition::TrailingPosition);
×
462
        connect(clearAction, SIGNAL(triggered()), this, SLOT(searchListClear()));
×
463
        updateListTab();
×
464

465
        connect(ui->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(changeTab(int)));
×
466
        connect(this, SIGNAL(visibleChanged(bool)), this, SLOT(refreshFocus(bool)));
×
467
        connect(StelApp::getInstance().getCore(), SIGNAL(updateSearchLists()), this, SLOT(updateListTab()));
×
468
        connect(GETSTELMODULE(NomenclatureMgr), SIGNAL(flagShowNomenclatureChanged(bool)), this, SLOT(updateListTab()));
×
469

470
        // Get data from previous session
471
        loadRecentSearches();
×
472

473
        // Create list model view
474
        ui->searchListView->setModel(searchListModel);
×
475
        searchListModel->setStringList(searchListModel->getValues());
×
476

477
        // Auto display recent searches
478
        QStringList recentMatches = listMatchingRecentObjects("", recentObjectSearchesData.maxSize, useStartOfWords);
×
479
        resetSearchResultDisplay(recentMatches, recentMatches);
×
480
        setPushButtonGotoSearch();
×
481

482
        // Update max size of "recent object searches"
483
        connect(ui->recentSearchSizeSpinBox, SIGNAL(editingFinished()), this, SLOT(recentSearchSizeEditingFinished()));
×
484
        // Clear data from recent search object
485
        connect(ui->recentSearchClearDataPushButton, SIGNAL(clicked()), this, SLOT(recentSearchClearDataClicked()));
×
486
        populateRecentSearch();
×
487
}
×
488

489
void SearchDialog::populateRecentSearch()
×
490
{
491
        // Tooltip for recentSearchSizeSpinBox
492
        QString toolTipComment = QString("%1: %2 | %3: %4 - %5 %6")
×
493
                        .arg(qc_("Default", "search tool"))
×
494
                        .arg(defaultMaxSize)
×
495
                        .arg(qc_("Range", "search tool"))
×
496
                        .arg(ui->recentSearchSizeSpinBox->minimum())
×
497
                        .arg(ui->recentSearchSizeSpinBox->maximum())
×
498
                        .arg(qc_("searches", "search tool"));
×
499
        ui->recentSearchSizeSpinBox->setToolTip(toolTipComment);
×
500
        setRecentSearchClearDataPushButton();
×
501
}
×
502

503
void SearchDialog::refreshFocus(bool state)
×
504
{
505
        if (state)
×
506
                ui->lineEditSearchSkyObject->setFocus();
×
507
}
×
508

509
void SearchDialog::changeTab(int index)
×
510
{
511
        if (index==0) // Search Tab
×
512
                ui->lineEditSearchSkyObject->setFocus();
×
513

514
        if (index==2) // Position
×
515
        {
516
                if (useFOVCenterMarker)
×
517
                        GETSTELMODULE(SpecialMarkersMgr)->setFlagFOVCenterMarker(true);
×
518
        }
519
        else
520
                GETSTELMODULE(SpecialMarkersMgr)->setFlagFOVCenterMarker(fovCenterMarkerState);
×
521

522
        if (index==3) // Lists
×
523
        {
524
                updateListTab();
×
525
                ui->searchInListLineEdit->setFocus();
×
526
        }
527
}
×
528

529
void SearchDialog::setHasSelectedFlag()
×
530
{
531
        flagHasSelectedText = true;
×
532
}
×
533

534
void SearchDialog::enableSimbadSearch(bool enable)
×
535
{
536
        useSimbad = enable;
×
537
        conf->setValue("search/flag_search_online", useSimbad);
×
538
        if (dialog && ui->simbadStatusLabel) ui->simbadStatusLabel->clear();
×
539
        if (dialog && ui->simbadCooStatusLabel) ui->simbadCooStatusLabel->clear();        
×
540
        if (dialog && ui->simbadTab) ui->simbadTab->setEnabled(enable);
×
541
        emit simbadUseChanged(enable);
×
542
}
×
543

544
void SearchDialog::setSimbadQueryDist(int dist)
×
545
{
546
        simbadDist=dist;
×
547
        conf->setValue("search/simbad_query_dist", simbadDist);
×
548
        emit simbadQueryDistChanged(dist);
×
549
}
×
550

551
void SearchDialog::setSimbadQueryCount(int count)
×
552
{
553
        simbadCount=count;
×
554
        conf->setValue("search/simbad_query_count", simbadCount);
×
555
        emit simbadQueryCountChanged(count);
×
556
}
×
557
void SearchDialog::setSimbadGetsIds(bool b)
×
558
{
559
        simbadGetIds=b;
×
560
        conf->setValue("search/simbad_query_IDs", b);
×
561
        emit simbadGetsIdsChanged(b);
×
562
}
×
563

564
void SearchDialog::setSimbadGetsSpec(bool b)
×
565
{
566
        simbadGetSpec=b;
×
567
        conf->setValue("search/simbad_query_spec", b);
×
568
        emit simbadGetsSpecChanged(b);
×
569
}
×
570

571
void SearchDialog::setSimbadGetsMorpho(bool b)
×
572
{
573
        simbadGetMorpho=b;
×
574
        conf->setValue("search/simbad_query_morpho", b);
×
575
        emit simbadGetsMorphoChanged(b);
×
576
}
×
577

578
void SearchDialog::setSimbadGetsTypes(bool b)
×
579
{
580
        simbadGetTypes=b;
×
581
        conf->setValue("search/simbad_query_types", b);
×
582
        emit simbadGetsTypesChanged(b);
×
583
}
×
584

585
void SearchDialog::setSimbadGetsDims(bool b)
×
586
{
587
        simbadGetDims=b;
×
588
        conf->setValue("search/simbad_query_dimensions", b);
×
589
        emit simbadGetsDimsChanged(b);
×
590
}
×
591

592
void SearchDialog::recentSearchSizeEditingFinished()
×
593
{
594
        // Update max size in dialog and user data
595
        int maxSize = ui->recentSearchSizeSpinBox->value();
×
596
        setRecentSearchSize(maxSize);
×
597
        // maxSize = recentObjectSearchesData.maxSize; // Might not be the same. BUT USELESS call, dead store!
598

599
        // Save maxSize to user's data
600
        saveRecentSearches();
×
601

602
        // Update search result on "Object" tab
603
        onSearchTextChanged(ui->lineEditSearchSkyObject->text());
×
604
}
×
605

606
void SearchDialog::recentSearchClearDataClicked()
×
607
{
608
        // Clear recent list from current run
609
        recentObjectSearchesData.recentList.clear();
×
610

611
        // Save empty list to user's data file
612
        saveRecentSearches();
×
613

614
        // Update search result on "Object" tab
615
        onSearchTextChanged(ui->lineEditSearchSkyObject->text());
×
616
}
×
617

618
void SearchDialog::setRecentSearchClearDataPushButton()
×
619
{
620
        // Enable clear button if recent list is greater than 0
621
        bool toEnable = recentObjectSearchesData.recentList.size() > 0;
×
622
        ui->recentSearchClearDataPushButton->setEnabled(toEnable);
×
623
        // Tool tip depends on recent list size
624
        QString toolTipText = toEnable ? q_("Clear search history: delete all search objects data") : q_("Clear search history: no data to delete");
×
625
        ui->recentSearchClearDataPushButton->setToolTip(toolTipText);
×
626
}
×
627

628
void SearchDialog::enableStartOfWordsAutofill(bool enable)
×
629
{
630
        useStartOfWords = enable;
×
631
        conf->setValue("search/flag_start_words", useStartOfWords);
×
632

633
        // Update search result on "Object" tab
634
        onSearchTextChanged(ui->lineEditSearchSkyObject->text());
×
635
}
×
636

637
void SearchDialog::enableLockPosition(bool enable)
×
638
{
639
        useLockPosition = enable;
×
640
        conf->setValue("search/flag_lock_position", useLockPosition);
×
641
}
×
642

643
void SearchDialog::enableFOVCenterMarker(bool enable)
×
644
{
645
        useFOVCenterMarker = enable;
×
646
        fovCenterMarkerState = GETSTELMODULE(SpecialMarkersMgr)->getFlagFOVCenterMarker();
×
647
        conf->setValue("search/flag_fov_center_marker", useFOVCenterMarker);
×
648
}
×
649

650
void SearchDialog::setSimpleStyle()
×
651
{
652
        ui->AxisXSpinBox->setVisible(false);
×
653
        ui->AxisXSpinBox->setVisible(false);
×
654
        ui->simbadStatusLabel->setVisible(false);
×
655
        ui->simbadCooStatusLabel->setVisible(false);
×
656
        ui->AxisXLabel->setVisible(false);
×
657
        ui->AxisYLabel->setVisible(false);
×
658
        ui->coordinateSystemLabel->setVisible(false);
×
659
        ui->coordinateSystemComboBox->setVisible(false);
×
660
}
×
661

662

663
void SearchDialog::manualPositionChanged()
×
664
{
665
        searchListModel->clearValues();
×
666
        StelCore* core = StelApp::getInstance().getCore();
×
667
        StelMovementMgr* mvmgr = GETSTELMODULE(StelMovementMgr);        
×
668
        Vec3d pos;        
×
669
        double spinLong=ui->AxisXSpinBox->valueRadians();
×
670
        double spinLat=ui->AxisYSpinBox->valueRadians();
×
671

672
        // Since 0.15: proper handling of aimUp vector. This does not depend on the searched coordinate system, but on the MovementManager's C.S.
673
        // However, if those are identical, we have a problem when we want to look right into the pole. (e.g. zenith), which requires a special up vector.
674
        // aimUp depends on MovementMgr::MountMode mvmgr->mountMode!
675
        mvmgr->setViewUpVector(Vec3d(0., 0., 1.));
×
676
        Vec3d aimUp = mvmgr->getViewUpVectorJ2000();
×
677
        StelMovementMgr::MountMode mountMode=mvmgr->getMountMode();
×
678

679
        switch (getCurrentCoordinateSystem())
×
680
        {
681
                case equatorialJ2000:
×
682
                {
683
                        StelUtils::spheToRect(spinLong, spinLat, pos);
×
684
                        if ( (mountMode==StelMovementMgr::MountEquinoxEquatorial) && (fabs(spinLat)> (0.9*M_PI_2)) )
×
685
                        {
686
                                // make up vector more stable.
687
                                // Strictly mount should be in a new J2000 mode, but this here also stabilizes searching J2000 coordinates.
688
                                mvmgr->setViewUpVector(Vec3d(-cos(spinLong), -sin(spinLong), 0.) * (spinLat>0. ? 1. : -1. ));
×
689
                                aimUp=mvmgr->getViewUpVectorJ2000();
×
690
                        }
691
                        break;
×
692
                }
693
                case equatorial:
×
694
                {
695
                        StelUtils::spheToRect(spinLong, spinLat, pos);
×
696
                        pos = core->equinoxEquToJ2000(pos, StelCore::RefractionOff);
×
697

698
                        if ( (mountMode==StelMovementMgr::MountEquinoxEquatorial) && (fabs(spinLat)> (0.9*M_PI_2)) )
×
699
                        {
700
                                // make up vector more stable.
701
                                mvmgr->setViewUpVector(Vec3d(-cos(spinLong), -sin(spinLong), 0.) * (spinLat>0. ? 1. : -1. ));
×
702
                                aimUp=mvmgr->getViewUpVectorJ2000();
×
703
                        }
704
                        break;
×
705
                }
706
                case horizontal:
×
707
                {
708
                        double cx;
709
                        cx = 3.*M_PI - spinLong; // N is zero, E is 90 degrees
×
710
                        if (cx > 2.*M_PI)
×
711
                                cx -= 2.*M_PI;
×
712
                        StelUtils::spheToRect(cx, spinLat, pos);
×
713
                        pos = core->altAzToJ2000(pos, StelCore::RefractionOff);
×
714
                        core->setTimeRate(0.);
×
715

716
                        if ( (mountMode==StelMovementMgr::MountAltAzimuthal) && (fabs(spinLat)> (0.9*M_PI_2)) )
×
717
                        {
718
                                // make up vector more stable.
719
                                mvmgr->setViewUpVector(Vec3d(-cos(cx), -sin(cx), 0.) * (spinLat>0. ? 1. : -1. ));
×
720
                                aimUp=mvmgr->getViewUpVectorJ2000();
×
721
                        }
722
                        break;
×
723
                }
724
                case galactic:
×
725
                {
726
                        StelUtils::spheToRect(spinLong, spinLat, pos);
×
727
                        pos = core->galacticToJ2000(pos);
×
728
                        if ( (mountMode==StelMovementMgr::MountGalactic) && (fabs(spinLat)> (0.9*M_PI_2)) )
×
729
                        {
730
                                // make up vector more stable.
731
                                mvmgr->setViewUpVector(Vec3d(-cos(spinLong), -sin(spinLong), 0.) * (spinLat>0. ? 1. : -1. ));
×
732
                                aimUp=mvmgr->getViewUpVectorJ2000();
×
733
                        }
734
                        break;
×
735
                }
736
                case supergalactic:
×
737
                {
738
                        StelUtils::spheToRect(spinLong, spinLat, pos);
×
739
                        pos = core->supergalacticToJ2000(pos);
×
740
                        if ( (mountMode==StelMovementMgr::MountSupergalactic) && (fabs(spinLat)> (0.9*M_PI_2)) )
×
741
                        {
742
                                // make up vector more stable.
743
                                mvmgr->setViewUpVector(Vec3d(-cos(spinLong), -sin(spinLong), 0.) * (spinLat>0. ? 1. : -1. ));
×
744
                                aimUp=mvmgr->getViewUpVectorJ2000();
×
745
                        }
746
                        break;
×
747
                }
748
                case eclipticJ2000:
×
749
                {
750
                        double ra, dec;
751
                        StelUtils::eclToEqu(spinLong, spinLat, GETSTELMODULE(SolarSystem)->getEarth()->getRotObliquity(2451545.0), &ra, &dec);
×
752
                        StelUtils::spheToRect(ra, dec, pos);
×
753
                        break;
×
754
                }
755
                case ecliptic:
×
756
                {
757
                        double ra, dec;
758
                        StelUtils::eclToEqu(spinLong, spinLat, GETSTELMODULE(SolarSystem)->getEarth()->getRotObliquity(core->getJDE()), &ra, &dec);
×
759
                        StelUtils::spheToRect(ra, dec, pos);
×
760
                        pos = core->equinoxEquToJ2000(pos, StelCore::RefractionOff);
×
761
                        break;
×
762
                }
763
        }
764
        mvmgr->setFlagTracking(false);
×
765
        mvmgr->moveToJ2000(pos, aimUp, mvmgr->getAutoMoveDuration());
×
766
        mvmgr->setFlagLockEquPos(useLockPosition);
×
767
}
×
768

769
void SearchDialog::onSearchTextChanged(const QString& text)
×
770
{
771
        clearSimbadText(StelModule::ReplaceSelection);
×
772
        // This block needs to go before the trimmedText.isEmpty() or the SIMBAD result does not
773
        // get properly cleared.
774
        if (useSimbad)
×
775
        {
776
                if (simbadReply)
×
777
                {
778
                        disconnect(simbadReply, SIGNAL(statusChanged()), this, SLOT(onSimbadStatusChanged()));
×
779
                        delete simbadReply;
×
780
                        simbadReply=nullptr;
×
781
                }
782
                simbadResults.clear();
×
783
        }
784

785
        // Use to adjust matches to be within range of maxNbItem
786
        int maxNbItem;
787
        QString trimmedText = text.trimmed();
×
788
        if (trimmedText.isEmpty())
×
789
        {
790
                searchListModel->clearValues();
×
791

792
                maxNbItem = recentObjectSearchesData.maxSize;
×
793
                // Auto display recent searches
794
                QStringList recentMatches = listMatchingRecentObjects(trimmedText, maxNbItem, useStartOfWords);
×
795
                resetSearchResultDisplay(recentMatches, recentMatches);
×
796

797
                ui->simbadStatusLabel->setText("");
×
798
                ui->simbadCooStatusLabel->setText("");
×
799
                setPushButtonGotoSearch();
×
800
        }
×
801
        else
802
        {
803
                if (useSimbad)
×
804
                {
805
                        simbadReply = simbadSearcher->lookup(simbadServerUrl, trimmedText, 4);
×
806
                        onSimbadStatusChanged();
×
807
                        connect(simbadReply, SIGNAL(statusChanged()), this, SLOT(onSimbadStatusChanged()));
×
808
                }
809

810
                // Get possible objects
811
                QStringList matches;
×
812
                QStringList recentMatches;
×
813
                QStringList allMatches;
×
814

815
                QString greekText = substituteGreek(trimmedText);
×
816

817
                int trimmedTextMaxNbItem = 13;
×
818
                int greekTextMaxMbItem = 0;
×
819

820
                if(greekText != trimmedText)
×
821
                {
822
                        trimmedTextMaxNbItem = 8;
×
823
                        greekTextMaxMbItem = 18;
×
824

825
                        // Get recent matches
826
                        // trimmedText
827
                        recentMatches = listMatchingRecentObjects(trimmedText, trimmedTextMaxNbItem, useStartOfWords);
×
828
                        // greekText
829
                        recentMatches += listMatchingRecentObjects(greekText, (greekTextMaxMbItem - recentMatches.size()), useStartOfWords);
×
830

831
                        // Get rest of matches
832
                        // trimmedText
833
                        matches = objectMgr->listMatchingObjects(trimmedText, trimmedTextMaxNbItem, useStartOfWords);
×
834
                        // greekText
835
                        matches += objectMgr->listMatchingObjects(greekText, (greekTextMaxMbItem - matches.size()), useStartOfWords);
×
836
                }
837
                else
838
                {
839
                        trimmedTextMaxNbItem = 13;
×
840

841
                        // Get recent matches
842
                        recentMatches = listMatchingRecentObjects(trimmedText, trimmedTextMaxNbItem, useStartOfWords);
×
843

844
                        // Get rest of matches
845
                        matches  = objectMgr->listMatchingObjects(trimmedText, trimmedTextMaxNbItem, useStartOfWords);
×
846
                }
847
                // Check in case either number changes since they were
848
                // hard coded
849
                maxNbItem  = qMax(greekTextMaxMbItem, trimmedTextMaxNbItem);
×
850

851
                // Clean up matches
852
                adjustMatchesResult(allMatches, recentMatches, matches, maxNbItem);
×
853

854
                // Updates values
855
                resetSearchResultDisplay(allMatches, recentMatches);
×
856

857
                // Update push button enabled state
858
                setPushButtonGotoSearch();
×
859
        }
×
860

861
        // Goto object when clicking in list
862
        connect(ui->searchListView, SIGNAL(clicked(const QModelIndex&)), this, SLOT(gotoObject(const QModelIndex&)), Qt::UniqueConnection);
×
863
        connect(ui->searchListView, SIGNAL(activated(const QModelIndex&)), this, SLOT(gotoObject(const QModelIndex&)), Qt::UniqueConnection);
×
864
}
×
865

866
void SearchDialog::updateRecentSearchList(const QString &nameI18n)
×
867
{
868
        if(nameI18n.isEmpty())
×
869
                return;
×
870

871
        // Prepend & remove duplicates
872
        recentObjectSearchesData.recentList.prepend(nameI18n);
×
873
        recentObjectSearchesData.recentList.removeDuplicates();
×
874

875
        adjustRecentList(recentObjectSearchesData.maxSize);
×
876

877
        // Auto display recent searches
878
        QStringList recentMatches = listMatchingRecentObjects("", recentObjectSearchesData.maxSize, useStartOfWords);
×
879
        resetSearchResultDisplay(recentMatches, recentMatches);
×
880
}
×
881

882
void SearchDialog::adjustRecentList(int maxSize)
×
883
{        
884
        // Check if max size was updated recently
885
        maxSize = (maxSize >= 0) ? maxSize : recentObjectSearchesData.maxSize;
×
886
        recentObjectSearchesData.maxSize = maxSize;
×
887

888
        // Max amount of saved values "allowed"
889
        int spinBoxMaxSize = ui->recentSearchSizeSpinBox->maximum();
×
890

891
        // Only removing old searches if the list grows larger than the largest
892
        // "allowed" size (to retain data in case the user switches from
893
        // high to low size)
894
        if( recentObjectSearchesData.recentList.size() > spinBoxMaxSize)
×
895
                recentObjectSearchesData.recentList = recentObjectSearchesData.recentList.mid(0, spinBoxMaxSize);
×
896
}
×
897

898
void SearchDialog::adjustMatchesResult(QStringList &allMatches, QStringList& recentMatches, QStringList& matches, int maxNbItem)
×
899
{
900
        int tempSize;
901
        QStringList tempMatches; // unsorted matches use for calculation
×
902
        // not displaying
903

904
        // remove possible duplicates from completion list
905
        matches.removeDuplicates();
×
906

907
        matches.sort(Qt::CaseInsensitive);
×
908
        // objects with short names should be searched first
909
        // examples: Moon, Hydra (moon); Jupiter, Ghost of Jupiter
910
        stringLengthCompare comparator;
911
        std::sort(matches.begin(), matches.end(), comparator);
×
912

913
        // Adjust recent matches to preferred max size
914
        recentMatches = recentMatches.mid(0, recentObjectSearchesData.maxSize);
×
915

916
        // Find total size of both matches
917
        tempMatches << recentMatches << matches; // unsorted
×
918
        tempMatches.removeDuplicates();
×
919
        tempSize = tempMatches.size();
×
920

921
        // Adjust match size to be within range
922
        if(tempSize>maxNbItem)
×
923
        {
924
                int i = tempSize - maxNbItem;
×
925
                matches = matches.mid(0, matches.size() - i);
×
926
        }
927

928
        // Combine list: ordered by recent searches then relevance
929
        allMatches << recentMatches << matches;
×
930

931
        // Remove possible duplicates from both listQSt
932
        allMatches.removeDuplicates();
×
933
}
×
934

935

936
void SearchDialog::resetSearchResultDisplay(QStringList allMatches,
×
937
                                               QStringList recentMatches)
938
{
939
        // Updates values
940
        searchListModel->appendValues(allMatches);
×
941
        searchListModel->appendRecentValues(recentMatches);
×
942

943
        // Update display
944
        searchListModel->setValues(allMatches, recentMatches);
×
945
        searchListModel->selectFirst();
×
946

947
        // Update highlight to top
948
        ui->searchListView->scrollToTop();
×
949
        int row = searchListModel->getSelectedIdx();
×
950
        ui->searchListView->setCurrentIndex(searchListModel->index(row));
×
951

952
        // Enable clear data button
953
        setRecentSearchClearDataPushButton();
×
954
}
×
955

956
void SearchDialog::setPushButtonGotoSearch()
×
957
{
958
        // Empty search and empty recently search object list
959
        if (searchListModel->isEmpty() && (recentObjectSearchesData.recentList.size() == 0))
×
960
                ui->pushButtonGotoSearchSkyObject->setEnabled(false); // Do not enable search button
×
961
        else
962
                ui->pushButtonGotoSearchSkyObject->setEnabled(true); // Do enable search  button
×
963
}
×
964

965
void SearchDialog::loadRecentSearches()
×
966
{
967
        QVariantMap map;
×
968
        QFile jsonFile(recentObjectSearchesJsonPath);
×
969
        if(!jsonFile.open(QIODevice::ReadOnly))
×
970
        {
971
                qWarning() << "[Search] Can not open data file for recent searches"
×
972
                           << QDir::toNativeSeparators(recentObjectSearchesJsonPath);
×
973

974
                // Use default value for recent search size
975
                setRecentSearchSize(ui->recentSearchSizeSpinBox->value());
×
976
        }
977
        else
978
        {
979
                try
980
                {
981
                        int readMaxSize;
982

983
                        map = StelJsonParser::parse(jsonFile.readAll()).toMap();
×
984
                        jsonFile.close();
×
985

986
                        QVariantMap recentSearchData = map.value("recentObjectSearches").toMap();
×
987

988
                        // Get user's maxSize data (if possible)
989
                        readMaxSize = recentSearchData.value("maxSize").toInt();
×
990
                         // Non-negative size only
991
                        recentObjectSearchesData.maxSize = (readMaxSize >= 0) ? readMaxSize : recentObjectSearchesData.maxSize;
×
992

993
                        // Update dialog size to match user's preference
994
                        ui->recentSearchSizeSpinBox->setValue(recentObjectSearchesData.maxSize);
×
995

996
                        // Get user's recentList data (if possible)
997
                        recentObjectSearchesData.recentList = recentSearchData.value("recentList").toStringList();
×
998
                }
×
999
                catch (std::runtime_error &e)
×
1000
                {
1001
                        qWarning() << "[Search] File format is Wrong! Error:"
×
1002
                                   << e.what();
×
1003
                        return;
×
1004
                }
×
1005
        }
1006
}
×
1007

1008
void SearchDialog::saveRecentSearches()
×
1009
{
1010
        if(recentObjectSearchesJsonPath.isEmpty())
×
1011
        {
1012
                qWarning() << "[Search] Error in saving recent object searches";
×
1013
                return;
×
1014
        }
1015

1016
        QFile jsonFile(recentObjectSearchesJsonPath);
×
1017
        if(!jsonFile.open(QFile::WriteOnly | QFile::Text))
×
1018
        {
1019
                qWarning() << "[Search] Recent search could not be save. A file can not be open for writing:"
×
1020
                           << QDir::toNativeSeparators(recentObjectSearchesJsonPath);
×
1021
                return;
×
1022
        }
1023

1024
        QVariantMap rslDataList;
×
1025
        rslDataList.insert("maxSize", recentObjectSearchesData.maxSize);
×
1026
        rslDataList.insert("recentList", recentObjectSearchesData.recentList);
×
1027
        
1028
        QVariantMap rsList;
×
1029
        rsList.insert("recentObjectSearches", rslDataList);
×
1030

1031
        // Convert the tree to JSON
1032
        StelJsonParser::write(rsList, &jsonFile);
×
1033
        jsonFile.flush();
×
1034
        jsonFile.close();
×
1035
}
×
1036

1037
QStringList SearchDialog::listMatchingRecentObjects(const QString& objPrefix, int maxNbItem, bool useStartOfWords) const
×
1038
{
1039
        QStringList result;
×
1040

1041
        if(maxNbItem <= 0)
×
1042
                return result;
×
1043

1044
        // For all recent objects:
1045
        for (int i = 0; i < recentObjectSearchesData.recentList.size(); i++)
×
1046
        {
1047
                bool toAppend = useStartOfWords ? recentObjectSearchesData.recentList[i].startsWith(objPrefix, Qt::CaseInsensitive)
×
1048
                                                : recentObjectSearchesData.recentList[i].contains(objPrefix, Qt::CaseInsensitive);
×
1049

1050
                if(toAppend)
×
1051
                        result.append(recentObjectSearchesData.recentList[i]);
×
1052

1053
                if (result.size() >= maxNbItem)
×
1054
                        break;
×
1055
        }
1056
        return result;
×
1057
}
×
1058

1059

1060
void SearchDialog::lookupCoordinates()
×
1061
{
1062
        if (!useSimbad)
×
1063
                return;
×
1064

1065
        StelCore * core=StelApp::getInstance().getCore();
×
1066
        const QList<StelObjectP>& sel=GETSTELMODULE(StelObjectMgr)->getSelectedObject();
×
1067
        if (sel.length()==0)
×
1068
                return;
×
1069

1070
        Vec3d coords=sel.at(0)->getJ2000EquatorialPos(core);
×
1071

1072
        simbadReply = simbadSearcher->lookupCoords(simbadServerUrl, coords, getSimbadQueryCount(), 500,
×
1073
                                                   getSimbadQueryDist(), getSimbadGetsIds(), getSimbadGetsTypes(),
×
1074
                                                   getSimbadGetsSpec(), getSimbadGetsMorpho(), getSimbadGetsDims());
×
1075
        onSimbadStatusChanged();
×
1076
        connect(simbadReply, SIGNAL(statusChanged()), this, SLOT(onSimbadStatusChanged()));
×
1077
}
1078

1079
void SearchDialog::clearSimbadText(StelModule::StelModuleSelectAction)
×
1080
{
1081
        ui->simbadCooResultsTextBrowser->clear();
×
1082
}
×
1083

1084
// Called when the current simbad query status changes
1085
void SearchDialog::onSimbadStatusChanged()
×
1086
{
1087
        Q_ASSERT(simbadReply);
×
1088
        int index = ui->tabWidget->currentIndex();
×
1089
        QString info;
×
1090
        if (simbadReply->getCurrentStatus()==SimbadLookupReply::SimbadLookupErrorOccured)
×
1091
        {
1092
                info = QString("%1: %2").arg(q_("Simbad Lookup Error"), simbadReply->getErrorString());
×
1093
                index==1 ? ui->simbadCooStatusLabel->setText(info) : ui->simbadStatusLabel->setText(info);
×
1094
                setPushButtonGotoSearch();
×
1095
                ui->simbadCooResultsTextBrowser->clear();
×
1096
        }
1097
        else
1098
        {
1099
                info = QString("%1: %2").arg(q_("Simbad Lookup"), simbadReply->getCurrentStatusString());
×
1100
                index==1 ? ui->simbadCooStatusLabel->setText(info) : ui->simbadStatusLabel->setText(info);
×
1101
                // Query not over, don't disable button
1102
                ui->pushButtonGotoSearchSkyObject->setEnabled(true);
×
1103
        }
1104

1105
        if (simbadReply->getCurrentStatus()==SimbadLookupReply::SimbadLookupFinished)
×
1106
        {
1107
                simbadResults = simbadReply->getResults();
×
1108
                searchListModel->appendValues(simbadResults.keys());
×
1109
                // Update push button enabled state
1110
                setPushButtonGotoSearch();
×
1111
        }
1112

1113
        if (simbadReply->getCurrentStatus()==SimbadLookupReply::SimbadCoordinateLookupFinished)
×
1114
        {
1115
                QString ret = simbadReply->getResult();
×
1116
                ui->simbadCooResultsTextBrowser->setText(ret);
×
1117
        }
×
1118

1119
        if (simbadReply->getCurrentStatus()!=SimbadLookupReply::SimbadLookupQuerying)
×
1120
        {
1121
                disconnect(simbadReply, SIGNAL(statusChanged()), this, SLOT(onSimbadStatusChanged()));
×
1122
                delete simbadReply;
×
1123
                simbadReply=nullptr;
×
1124

1125
                // Update push button enabled state
1126
                setPushButtonGotoSearch();
×
1127
        }
1128
}
×
1129

1130
void SearchDialog::greekLetterClicked()
×
1131
{
1132
        QPushButton *sender = reinterpret_cast<QPushButton *>(this->sender());
×
1133
        QLineEdit* sso = ui->lineEditSearchSkyObject;
×
1134
        QString text;
×
1135
        if (sender)
×
1136
        {
1137
                shiftPressed ? text = sender->text().toUpper() : text = sender->text();
×
1138
                if (flagHasSelectedText)
×
1139
                {
1140
                        sso->setText(text);
×
1141
                        flagHasSelectedText = false;
×
1142
                }
1143
                else
1144
                        sso->setText(sso->text() + text);
×
1145
        }
1146
        sso->setFocus();
×
1147
}
×
1148

1149
void SearchDialog::gotoObject()
×
1150
{
1151
        gotoObject(searchListModel->getSelected());
×
1152
}
×
1153

1154
void SearchDialog::gotoObject(const QString &nameI18n)
×
1155
{
1156
        if (nameI18n.isEmpty())
×
1157
                return;
×
1158

1159
        // Save recent search list
1160
        updateRecentSearchList(nameI18n);
×
1161
        saveRecentSearches();
×
1162

1163
        StelMovementMgr* mvmgr = GETSTELMODULE(StelMovementMgr);
×
1164
        if (simbadResults.contains(nameI18n))
×
1165
        {
1166
                if (objectMgr->findAndSelect(nameI18n))
×
1167
                {
1168
                        const QList<StelObjectP> newSelected = objectMgr->getSelectedObject();
×
1169
                        if (!newSelected.empty())
×
1170
                        {
1171
                                close();
×
1172
                                ui->lineEditSearchSkyObject->setText(""); // https://wiki.qt.io/Technical_FAQ#Why_does_the_memory_keep_increasing_when_repeatedly_pasting_text_and_calling_clear.28.29_in_a_QLineEdit.3F
×
1173

1174
                                // Can't point to home planet
1175
                                if (newSelected[0]->getEnglishName()!=StelApp::getInstance().getCore()->getCurrentLocation().planetName)
×
1176
                                {
1177
                                        mvmgr->moveToObject(newSelected[0], mvmgr->getAutoMoveDuration());
×
1178
                                        mvmgr->setFlagTracking(true);
×
1179
                                }
1180
                                else
1181
                                        GETSTELMODULE(StelObjectMgr)->unSelect();
×
1182
                        }
1183
                }
×
1184
                else
1185
                {
1186
                        close();
×
1187
                        GETSTELMODULE(CustomObjectMgr)->addCustomObject(nameI18n, simbadResults[nameI18n]);
×
1188
                        ui->lineEditSearchSkyObject->clear();
×
1189
                        searchListModel->clearValues();
×
1190
                        if (objectMgr->findAndSelect(nameI18n))
×
1191
                        {
1192
                                const QList<StelObjectP> newSelected = objectMgr->getSelectedObject();
×
1193
                                // Can't point to home planet
1194
                                if (newSelected[0]->getEnglishName()!=StelApp::getInstance().getCore()->getCurrentLocation().planetName)
×
1195
                                {
1196
                                        mvmgr->moveToObject(newSelected[0], mvmgr->getAutoMoveDuration());
×
1197
                                        mvmgr->setFlagTracking(true);
×
1198
                                }
1199
                                else
1200
                                        GETSTELMODULE(StelObjectMgr)->unSelect();
×
1201
                        }
×
1202
                }
1203
        }
1204
        else if (objectMgr->findAndSelectI18n(nameI18n) || objectMgr->findAndSelect(nameI18n))
×
1205
        {
1206
                const QList<StelObjectP> newSelected = objectMgr->getSelectedObject();
×
1207
                if (!newSelected.empty())
×
1208
                {
1209
                        close();
×
1210
                        ui->lineEditSearchSkyObject->clear();
×
1211

1212
                        // Can't point to home planet
1213
                        if (newSelected[0]->getEnglishName()!=StelApp::getInstance().getCore()->getCurrentLocation().planetName)
×
1214
                        {
1215
                                mvmgr->moveToObject(newSelected[0], mvmgr->getAutoMoveDuration());
×
1216
                                mvmgr->setFlagTracking(true);
×
1217
                        }
1218
                        else
1219
                                GETSTELMODULE(StelObjectMgr)->unSelect();
×
1220
                }
1221
        }
×
1222
        simbadResults.clear();
×
1223
}
1224

1225
void SearchDialog::gotoObject(const QString &nameI18n, const QString &objType)
×
1226
{
1227
        if (nameI18n.isEmpty())
×
1228
                return;
×
1229

1230
        StelMovementMgr* mvmgr = GETSTELMODULE(StelMovementMgr);
×
1231
        if (objectMgr->findAndSelectI18n(nameI18n, objType) || objectMgr->findAndSelect(nameI18n, objType))
×
1232
        {
1233
                const QList<StelObjectP> newSelected = objectMgr->getSelectedObject();
×
1234
                if (!newSelected.empty())
×
1235
                {
1236
                        close();
×
1237
                        ui->lineEditSearchSkyObject->clear();
×
1238
                        
1239
                        // Can't point to home planet
1240
                        if (newSelected[0]->getEnglishName()!=StelApp::getInstance().getCore()->getCurrentLocation().planetName)
×
1241
                        {
1242
                                mvmgr->moveToObject(newSelected[0], mvmgr->getAutoMoveDuration());
×
1243
                                mvmgr->setFlagTracking(true);
×
1244
                        }
1245
                        else
1246
                                GETSTELMODULE(StelObjectMgr)->unSelect();
×
1247
                }
1248
        }
×
1249
}
1250

1251
void SearchDialog::gotoObject(const QModelIndex &modelIndex)
×
1252
{
1253
        gotoObject(modelIndex.model()->data(modelIndex, Qt::DisplayRole).toString());
×
1254
}
×
1255

1256
void SearchDialog::gotoObjectWithType(const QModelIndex &modelIndex)
×
1257
{
1258
        QString objType, objClass = ui->objectTypeComboBox->currentData(Qt::UserRole).toString();
×
1259
        if (objClass.contains(":"))
×
1260
        {
1261
                #if (QT_VERSION>=QT_VERSION_CHECK(5, 14, 0))
1262
                QStringList list = objClass.split(":", Qt::SkipEmptyParts);
×
1263
                #else
1264
                QStringList list = objClass.split(":", QString::SkipEmptyParts);
1265
                #endif
1266
                objType = list.at(0);
×
1267
        }
×
1268
        else
1269
                objType = objClass;
×
1270

1271
        objType.replace("Mgr","");
×
1272
        objType.replace("SolarSystem","Planet");
×
1273
        objType.replace("Nomenclature","NomenclatureItem");
×
1274
        // plug-ins
1275
        objType.replace("Supernovae","Supernova");
×
1276
        objType.replace("Novae","Nova");
×
1277
        objType.replace("Exoplanets","Exoplanet");
×
1278
        objType.replace("Pulsars","Pulsar");
×
1279
        objType.replace("Quasars","Quasar");
×
1280
        objType.replace("MeteorShowers","MeteorShower");
×
1281

1282
        gotoObject(modelIndex.model()->data(modelIndex, Qt::DisplayRole).toString(), objType);
×
1283
}
×
1284

1285
void SearchDialog::searchListClear()
×
1286
{
1287
        ui->searchInListLineEdit->setText(""); // https://wiki.qt.io/Technical_FAQ#Why_does_the_memory_keep_increasing_when_repeatedly_pasting_text_and_calling_clear.28.29_in_a_QLineEdit.3F
×
1288
}
×
1289

1290
bool SearchDialog::eventFilter(QObject*, QEvent *event)
×
1291
{
1292
        if (event->type() == QEvent::KeyPress)
×
1293
        {
1294
                QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
×
1295

1296
                if (keyEvent->key() == Qt::Key_Shift)
×
1297
                {
1298
                        shiftPressed = true;
×
1299
                        event->accept();
×
1300
                        return true;
×
1301
                }
1302
        }
1303
        if (event->type() == QEvent::KeyRelease)
×
1304
        {
1305
                QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
×
1306

1307
                if (keyEvent->key() == Qt::Key_Tab || keyEvent->key() == Qt::Key_Down)
×
1308
                {
1309
                        searchListModel->selectNext();
×
1310
                        int row = searchListModel->getSelectedIdx();
×
1311
                        ui->searchListView->scrollTo(searchListModel->index(row));
×
1312
                        ui->searchListView->setCurrentIndex(searchListModel->index(row));
×
1313
                        event->accept();
×
1314
                        return true;
×
1315
                }
1316
                if (keyEvent->key() == Qt::Key_Up)
×
1317
                {
1318
                        searchListModel->selectPrevious();
×
1319
                        int row = searchListModel->getSelectedIdx();
×
1320
                        ui->searchListView->scrollTo(searchListModel->index(row));
×
1321
                        ui->searchListView->setCurrentIndex(searchListModel->index(row));
×
1322
                        event->accept();
×
1323
                        return true;
×
1324
                }
1325
                if (keyEvent->key() == Qt::Key_Shift)
×
1326
                {
1327
                        shiftPressed = false;
×
1328
                        event->accept();
×
1329
                        return true;
×
1330
                }
1331
        }
1332
        if (event->type() == QEvent::Show)
×
1333
        {
1334
                if (!extSearchText.isEmpty())
×
1335
                {
1336
                        ui->lineEditSearchSkyObject->setText(extSearchText);
×
1337
                        ui->lineEditSearchSkyObject->selectAll();
×
1338
                        extSearchText.clear();
×
1339
                }
1340
        }
1341
        return false;
×
1342
}
1343

1344
QString SearchDialog::substituteGreek(const QString& keyString)
×
1345
{
1346
        if (!keyString.contains(' '))
×
1347
                return getGreekLetterByName(keyString);
×
1348
        else
1349
        {
1350
                #if (QT_VERSION>=QT_VERSION_CHECK(5, 14, 0))
1351
                QStringList nameComponents = keyString.split(" ", Qt::SkipEmptyParts);
×
1352
                #else
1353
                QStringList nameComponents = keyString.split(" ", QString::SkipEmptyParts);
1354
                #endif
1355
                if(!nameComponents.empty())
×
1356
                        nameComponents[0] = getGreekLetterByName(nameComponents[0]);
×
1357
                return nameComponents.join(" ");
×
1358
        }
×
1359
}
1360

1361
QString SearchDialog::getGreekLetterByName(const QString& potentialGreekLetterName)
×
1362
{
1363
        if(staticData.greekLetters.contains(potentialGreekLetterName))
×
1364
                return staticData.greekLetters[potentialGreekLetterName];
×
1365

1366
        // There can be indices (e.g. "α1 Cen" instead of "α Cen A"), so strip
1367
        // any trailing digit.
1368
        int lastCharacterIndex = potentialGreekLetterName.length()-1;
×
1369
        if(potentialGreekLetterName.at(lastCharacterIndex).isDigit())
×
1370
        {
1371
                QChar digit = potentialGreekLetterName.at(lastCharacterIndex);
×
1372
                QString name = potentialGreekLetterName.left(lastCharacterIndex);
×
1373
                if(staticData.greekLetters.contains(name))
×
1374
                        return staticData.greekLetters[name] + digit;
×
1375
        }
×
1376

1377
        return potentialGreekLetterName;
×
1378
}
1379

1380
void SearchDialog::populateSimbadServerList()
×
1381
{
1382
        Q_ASSERT(ui->serverListComboBox);
×
1383

1384
        QComboBox* servers = ui->serverListComboBox;
×
1385
        //Save the current selection to be restored later
1386
        servers->blockSignals(true);
×
1387
        int index = servers->currentIndex();
×
1388
        QVariant selectedUrl = servers->itemData(index);
×
1389
        servers->clear();
×
1390
        //For each server, display the localized description and store the URL as user data.
1391
        servers->addItem(q_("University of Strasbourg (France)"), DEF_SIMBAD_URL);
×
1392
        servers->addItem(q_("Harvard University (USA)"), "http://simbad.harvard.edu/");
×
1393

1394
        //Restore the selection
1395
        index = servers->findData(selectedUrl, Qt::UserRole, Qt::MatchCaseSensitive);
×
1396
        servers->setCurrentIndex(index);
×
1397
        servers->model()->sort(0);
×
1398
        servers->blockSignals(false);
×
1399
}
×
1400

1401
void SearchDialog::setRecentSearchSize(int maxSize)
×
1402
{
1403
        adjustRecentList(maxSize);
×
1404
        saveRecentSearches();
×
1405
        conf->setValue("search/recentSearchSize", recentObjectSearchesData.maxSize);
×
1406
}
×
1407

1408
void SearchDialog::selectSimbadServer(int index)
×
1409
{
1410
        index < 0 ? simbadServerUrl = DEF_SIMBAD_URL : simbadServerUrl = ui->serverListComboBox->itemData(index).toString();
×
1411
        conf->setValue("search/simbad_server_url", simbadServerUrl);
×
1412
}
×
1413

1414
void SearchDialog::updateListView(int index)
×
1415
{
1416
        QString moduleId = ui->objectTypeComboBox->itemData(index).toString();
×
1417
        bool englishNames = ui->searchInEnglishCheckBox->isChecked();
×
1418
        ui->searchInListLineEdit->setText(""); // https://wiki.qt.io/Technical_FAQ#Why_does_the_memory_keep_increasing_when_repeatedly_pasting_text_and_calling_clear.28.29_in_a_QLineEdit.3F
×
1419
        ui->objectsListView->blockSignals(true);
×
1420
        ui->objectsListView->reset();
×
1421
        listModel->setStringList(objectMgr->listAllModuleObjects(moduleId, englishNames));
×
1422
        proxyModel->setSourceModel(listModel);
×
1423
        proxyModel->sort(0, Qt::AscendingOrder);
×
1424
        ui->objectsListView->blockSignals(false);
×
1425
        //bugfix: prevent multiple connections, which seems to have happened before
1426
        connect(ui->objectsListView, SIGNAL(clicked(const QModelIndex&)), this, SLOT(gotoObjectWithType(const QModelIndex&)), Qt::UniqueConnection);
×
1427
}
×
1428

1429
void SearchDialog::updateListTab()
×
1430
{
1431
        QVariant selectedObjectId;
×
1432
        QComboBox* objects = ui->objectTypeComboBox;
×
1433
        int index = objects->currentIndex();
×
1434
        if (index < 0)
×
1435
                selectedObjectId = QVariant("AsterismMgr"); // Let's enable "Asterisms" by default!
×
1436
        else
1437
                selectedObjectId = objects->itemData(index, Qt::UserRole);
×
1438

1439
        if (StelApp::getInstance().getLocaleMgr().getAppLanguage().startsWith("en"))
×
1440
                ui->searchInEnglishCheckBox->hide(); // hide "names in English" checkbox
×
1441
        else
1442
                ui->searchInEnglishCheckBox->show();
×
1443
        objects->blockSignals(true);
×
1444
        objects->clear();
×
1445
        QMap<QString, QString> modulesMap = objectMgr->objectModulesMap();
×
1446
        for (auto it = modulesMap.begin(); it != modulesMap.end(); ++it)
×
1447
        {
1448
                // List of objects is not empty, let's add name of module or section!
1449
                if (!objectMgr->listAllModuleObjects(it.key(), ui->searchInEnglishCheckBox->isChecked()).isEmpty())
×
1450
                        objects->addItem(q_(it.value()), QVariant(it.key()));
×
1451
        }
1452
        index = objects->findData(selectedObjectId, Qt::UserRole, Qt::MatchCaseSensitive);
×
1453
        objects->setCurrentIndex(index);
×
1454
        objects->model()->sort(0, Qt::AscendingOrder);
×
1455
        objects->blockSignals(false);
×
1456
        updateListView(objects->currentIndex());
×
1457
}
×
1458

1459
void SearchDialog::showContextMenu(const QPoint &pt)
×
1460
{
1461
        QMenu *menu = ui->lineEditSearchSkyObject->createStandardContextMenu();
×
1462
        menu->addSeparator();
×
1463
        QString clipText;
×
1464
        QClipboard *clipboard = QApplication::clipboard();
×
1465
        if (clipboard)
×
1466
                clipText = clipboard->text();
×
1467
        if (!clipText.isEmpty())
×
1468
        {
1469
                if (clipText.length()>12)
×
1470
                        clipText = clipText.right(9) + "...";
×
1471
                clipText = "\t(" + clipText + ")";
×
1472
        }
1473

1474
        menu->addAction(q_("Paste and Search") + clipText, this, SLOT(pasteAndGo()));
×
1475
        menu->exec(ui->lineEditSearchSkyObject->mapToGlobal(pt));
×
1476
        delete menu;
×
1477
}
×
1478

1479
void SearchDialog::pasteAndGo()
×
1480
{
1481
        // https://wiki.qt.io/Technical_FAQ#Why_does_the_memory_keep_increasing_when_repeatedly_pasting_text_and_calling_clear.28.29_in_a_QLineEdit.3F
1482
        ui->lineEditSearchSkyObject->setText(""); // clear current text
×
1483
        ui->lineEditSearchSkyObject->paste(); // paste text from clipboard
×
1484
        gotoObject(); // go to first found object
×
1485
}
×
1486

1487
void SearchDialog::setVisible(bool v)
×
1488
{
1489
        StelDialog::setVisible(v);
×
1490

1491
        // if from a previous search action, the first tab is shown but input line is not in focus,
1492
        // force focus on input line.
1493
        if (v && (ui->tabWidget->currentIndex()==0))
×
1494
        {
1495
                ui->lineEditSearchSkyObject->setFocus(Qt::PopupFocusReason);
×
1496
        }
1497
}
×
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