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

Stellarium / stellarium / 15670918640

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

push

github

alex-w
Updated data

14700 of 124846 relevant lines covered (11.77%)

18324.52 hits per line

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

0.0
/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
#include "StelSkyCultureMgr.hpp"
35

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

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

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

65
#include "SimbadSearcher.hpp"
66

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

163
// Start of members for class SearchDialog
164

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

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

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

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

203
        // Init CompletionListModel
204
        searchListModel = new CompletionListModel();
×
205

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

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

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

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

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

252
void SearchDialog::populateCoordinateSystemsList()
×
253
{
254
        Q_ASSERT(ui->coordinateSystemComboBox);
×
255

256
        QComboBox* csys = ui->coordinateSystemComboBox;
×
257

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

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

279
void SearchDialog::populateCoordinateAxis()
×
280
{
281
        bool withDecimalDegree = StelApp::getInstance().getFlagShowDecimalDegrees();
×
282
        bool xnormal = true;
×
283

284
        ui->AxisXSpinBox->setDecimals(2);
×
285
        ui->AxisYSpinBox->setDecimals(2);
×
286

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

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

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

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

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

378
        ui->lineEditSearchSkyObject->installEventFilter(this);        
×
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
        // following the current direction of FOV
400
        connect(GETSTELMODULE(StelMovementMgr), &StelMovementMgr::currentDirectionChanged, this, &SearchDialog::setCenterOfScreenCoordinates);
×
401
        setCenterOfScreenCoordinates();
×
402
        
403
        connect(ui->alphaPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
404
        connect(ui->betaPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
405
        connect(ui->gammaPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
406
        connect(ui->deltaPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
407
        connect(ui->epsilonPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
408
        connect(ui->zetaPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
409
        connect(ui->etaPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
410
        connect(ui->thetaPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
411
        connect(ui->iotaPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
412
        connect(ui->kappaPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
413
        connect(ui->lambdaPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
414
        connect(ui->muPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
415
        connect(ui->nuPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
416
        connect(ui->xiPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
417
        connect(ui->omicronPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
418
        connect(ui->piPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
419
        connect(ui->rhoPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
420
        connect(ui->sigmaPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
421
        connect(ui->tauPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
422
        connect(ui->upsilonPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
423
        connect(ui->phiPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
424
        connect(ui->chiPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
425
        connect(ui->psiPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
426
        connect(ui->omegaPushButton, SIGNAL(clicked(bool)), this, SLOT(greekLetterClicked()));
×
427

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

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

444
        connect(ui->checkBoxUseStartOfWords, SIGNAL(clicked(bool)), this, SLOT(enableStartOfWordsAutofill(bool)));
×
445
        ui->checkBoxUseStartOfWords->setChecked(useStartOfWords);
×
446
        connect(ui->checkBoxUseSortingByLength, SIGNAL(clicked(bool)), this, SLOT(enableSortingByLength(bool)));
×
447
        ui->checkBoxUseSortingByLength->setChecked(useLengthSorting);
×
448

449
        connect(ui->checkBoxFOVCenterMarker, SIGNAL(clicked(bool)), this, SLOT(enableFOVCenterMarker(bool)));
×
450
        ui->checkBoxFOVCenterMarker->setChecked(useFOVCenterMarker);
×
451

452
        connect(ui->checkBoxLockPosition, SIGNAL(clicked(bool)), this, SLOT(enableLockPosition(bool)));
×
453
        ui->checkBoxLockPosition->setChecked(useLockPosition);
×
454

455
        connect(ui->checkBoxAutoClosing, SIGNAL(clicked(bool)), this, SLOT(enableAutoClosing(bool)));
×
456
        ui->checkBoxAutoClosing->setChecked(useAutoClosing);
×
457

458
        // list views initialization
459
        listModel = new QStringListModel(this);
×
460
        proxyModel = new QSortFilterProxyModel(ui->objectsListView);
×
461
        proxyModel->setSourceModel(listModel);
×
462
        proxyModel->sort(0, Qt::AscendingOrder);
×
463
        proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
×
464
        ui->objectsListView->setModel(proxyModel);
×
465

466
        connect(ui->objectTypeComboBox, SIGNAL(activated(int)), this, SLOT(updateListView(int)));
×
467
        connect(ui->searchInListLineEdit, SIGNAL(textChanged(const QString&)), proxyModel, SLOT(setFilterWildcard(const QString&)));
×
468
        connect(ui->searchInEnglishCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateListTab()));
×
469
        QAction *clearAction = ui->searchInListLineEdit->addAction(QIcon(":/graphicGui/uieBackspaceInputButton.png"), QLineEdit::ActionPosition::TrailingPosition);
×
470
        connect(clearAction, SIGNAL(triggered()), this, SLOT(searchListClear()));
×
471
        updateListTab();
×
472

473
        connect(ui->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(changeTab(int)));
×
474
        connect(this, SIGNAL(visibleChanged(bool)), this, SLOT(refreshFocus(bool)));
×
475
        connect(StelApp::getInstance().getCore(), SIGNAL(updateSearchLists()), this, SLOT(updateListTab()));
×
476
        connect(GETSTELMODULE(NomenclatureMgr), SIGNAL(flagShowNomenclatureChanged(bool)), this, SLOT(updateListTab()));
×
477
        connect(&StelApp::getInstance().getSkyCultureMgr(), &StelSkyCultureMgr::currentSkyCultureIDChanged, this, &SearchDialog::updateListTab);
×
478

479
        // Get data from previous session
480
        loadRecentSearches();
×
481

482
        // Create list model view
483
        ui->searchListView->setModel(searchListModel);
×
484
        searchListModel->setStringList(searchListModel->getValues());
×
485

486
        // Auto display recent searches
487
        QStringList recentMatches = listMatchingRecentObjects("", recentObjectSearchesData.maxSize, useStartOfWords);
×
488
        resetSearchResultDisplay(recentMatches, recentMatches);
×
489
        setPushButtonGotoSearch();
×
490

491
        // Update max size of "recent object searches"
492
        connect(ui->recentSearchSizeSpinBox, SIGNAL(editingFinished()), this, SLOT(recentSearchSizeEditingFinished()));
×
493
        // Clear data from recent search object
494
        connect(ui->recentSearchClearDataPushButton, SIGNAL(clicked()), this, SLOT(recentSearchClearDataClicked()));
×
495
        populateRecentSearch();
×
496
}
×
497

498
void SearchDialog::populateRecentSearch()
×
499
{
500
        // Tooltip for recentSearchSizeSpinBox
501
        QString toolTipComment = QString("%1: %2 | %3: %4 - %5 %6")
×
502
                        .arg(qc_("Default", "search tool"))
×
503
                        .arg(defaultMaxSize)
×
504
                        .arg(qc_("Range", "search tool"))
×
505
                        .arg(ui->recentSearchSizeSpinBox->minimum())
×
506
                        .arg(ui->recentSearchSizeSpinBox->maximum())
×
507
                        .arg(qc_("searches", "search tool"));
×
508
        ui->recentSearchSizeSpinBox->setToolTip(toolTipComment);
×
509
        setRecentSearchClearDataPushButton();
×
510
}
×
511

512
void SearchDialog::refreshFocus(bool state)
×
513
{
514
        if (state)
×
515
                ui->lineEditSearchSkyObject->setFocus();
×
516
}
×
517

518
void SearchDialog::changeTab(int index)
×
519
{
520
        if (index==0) // Search Tab
×
521
                ui->lineEditSearchSkyObject->setFocus();
×
522

523
        if (index==2) // Position
×
524
        {
525
                setCenterOfScreenCoordinates();
×
526
                if (useFOVCenterMarker)
×
527
                        GETSTELMODULE(SpecialMarkersMgr)->setFlagFOVCenterMarker(true);
×
528
        }
529
        else
530
                GETSTELMODULE(SpecialMarkersMgr)->setFlagFOVCenterMarker(fovCenterMarkerState);
×
531

532
        if (index==3) // Lists
×
533
        {
534
                updateListTab();
×
535
                ui->searchInListLineEdit->setFocus();
×
536
        }
537
}
×
538

539
void SearchDialog::setHasSelectedFlag()
×
540
{
541
        flagHasSelectedText = true;
×
542
}
×
543

544
void SearchDialog::enableSimbadSearch(bool enable)
×
545
{
546
        useSimbad = enable;
×
547
        conf->setValue("search/flag_search_online", useSimbad);
×
548
        if (dialog && ui->simbadStatusLabel) ui->simbadStatusLabel->clear();
×
549
        if (dialog && ui->simbadCooStatusLabel) ui->simbadCooStatusLabel->clear();        
×
550
        if (dialog && ui->simbadTab) ui->simbadTab->setEnabled(enable);
×
551
        emit simbadUseChanged(enable);
×
552
}
×
553

554
void SearchDialog::setSimbadQueryDist(int dist)
×
555
{
556
        simbadDist=dist;
×
557
        conf->setValue("search/simbad_query_dist", simbadDist);
×
558
        emit simbadQueryDistChanged(dist);
×
559
}
×
560

561
void SearchDialog::setSimbadQueryCount(int count)
×
562
{
563
        simbadCount=count;
×
564
        conf->setValue("search/simbad_query_count", simbadCount);
×
565
        emit simbadQueryCountChanged(count);
×
566
}
×
567
void SearchDialog::setSimbadGetsIds(bool b)
×
568
{
569
        simbadGetIds=b;
×
570
        conf->setValue("search/simbad_query_IDs", b);
×
571
        emit simbadGetsIdsChanged(b);
×
572
}
×
573

574
void SearchDialog::setSimbadGetsSpec(bool b)
×
575
{
576
        simbadGetSpec=b;
×
577
        conf->setValue("search/simbad_query_spec", b);
×
578
        emit simbadGetsSpecChanged(b);
×
579
}
×
580

581
void SearchDialog::setSimbadGetsMorpho(bool b)
×
582
{
583
        simbadGetMorpho=b;
×
584
        conf->setValue("search/simbad_query_morpho", b);
×
585
        emit simbadGetsMorphoChanged(b);
×
586
}
×
587

588
void SearchDialog::setSimbadGetsTypes(bool b)
×
589
{
590
        simbadGetTypes=b;
×
591
        conf->setValue("search/simbad_query_types", b);
×
592
        emit simbadGetsTypesChanged(b);
×
593
}
×
594

595
void SearchDialog::setSimbadGetsDims(bool b)
×
596
{
597
        simbadGetDims=b;
×
598
        conf->setValue("search/simbad_query_dimensions", b);
×
599
        emit simbadGetsDimsChanged(b);
×
600
}
×
601

602
void SearchDialog::recentSearchSizeEditingFinished()
×
603
{
604
        // Update max size in dialog and user data
605
        int maxSize = ui->recentSearchSizeSpinBox->value();
×
606
        setRecentSearchSize(maxSize);
×
607
        // maxSize = recentObjectSearchesData.maxSize; // Might not be the same. BUT USELESS call, dead store!
608

609
        // Save maxSize to user's data
610
        saveRecentSearches();
×
611

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

616
void SearchDialog::recentSearchClearDataClicked()
×
617
{
618
        // Clear recent list from current run
619
        recentObjectSearchesData.recentList.clear();
×
620

621
        // Save empty list to user's data file
622
        saveRecentSearches();
×
623

624
        // Remove all SIMBAD's objects and save empty list to user's data file
625
        GETSTELMODULE(CustomObjectMgr)->removePersistentObjects();
×
626

627
        // Update search result on "Object" tab
628
        onSearchTextChanged(ui->lineEditSearchSkyObject->text());
×
629
}
×
630

631
void SearchDialog::setRecentSearchClearDataPushButton()
×
632
{
633
        // Enable clear button if recent list is not empty
634
        bool toEnable = !recentObjectSearchesData.recentList.isEmpty();
×
635
        ui->recentSearchClearDataPushButton->setEnabled(toEnable);
×
636
        // Tool tip depends on recent list size
637
        QString toolTipText = toEnable ? q_("Clear search history: delete all search objects data") : q_("Clear search history: no data to delete");
×
638
        ui->recentSearchClearDataPushButton->setToolTip(toolTipText);
×
639
}
×
640

641
void SearchDialog::enableStartOfWordsAutofill(bool enable)
×
642
{
643
        useStartOfWords = enable;
×
644
        conf->setValue("search/flag_start_words", useStartOfWords);
×
645

646
        // Update search result on "Object" tab
647
        onSearchTextChanged(ui->lineEditSearchSkyObject->text());
×
648
}
×
649

650
void SearchDialog::enableSortingByLength(bool enable)
×
651
{
652
        useLengthSorting = enable;
×
653
        conf->setValue("search/flag_sorting_length", useLengthSorting);
×
654

655
        // Update search result on "Object" tab
656
        onSearchTextChanged(ui->lineEditSearchSkyObject->text());
×
657
}
×
658

659
void SearchDialog::enableLockPosition(bool enable)
×
660
{
661
        useLockPosition = enable;
×
662
        conf->setValue("search/flag_lock_position", useLockPosition);
×
663
}
×
664

665
void SearchDialog::enableAutoClosing(bool enable)
×
666
{
667
        useAutoClosing = enable;
×
668
        conf->setValue("search/flag_auto_closing", useAutoClosing);
×
669
}
×
670

671
void SearchDialog::enableFOVCenterMarker(bool enable)
×
672
{
673
        useFOVCenterMarker = enable;
×
674
        fovCenterMarkerState = GETSTELMODULE(SpecialMarkersMgr)->getFlagFOVCenterMarker();
×
675
        conf->setValue("search/flag_fov_center_marker", useFOVCenterMarker);
×
676
}
×
677

678
void SearchDialog::setSimpleStyle()
×
679
{
680
        ui->AxisXSpinBox->setVisible(false);
×
681
        ui->AxisXSpinBox->setVisible(false);
×
682
        ui->simbadStatusLabel->setVisible(false);
×
683
        ui->simbadCooStatusLabel->setVisible(false);
×
684
        ui->AxisXLabel->setVisible(false);
×
685
        ui->AxisYLabel->setVisible(false);
×
686
        ui->coordinateSystemLabel->setVisible(false);
×
687
        ui->coordinateSystemComboBox->setVisible(false);
×
688
}
×
689

690
void SearchDialog::setCenterOfScreenCoordinates()
×
691
{
692
        StelCore *core = StelApp::getInstance().getCore();
×
693
        const auto projector = core->getProjection(StelCore::FrameJ2000, StelCore::RefractionMode::RefractionOff);        
×
694
        Vector2<qreal> cpos = projector->getViewportCenter();
×
695
        Vec3d centerPos;
×
696
        projector->unProject(cpos[0], cpos[1], centerPos);
×
697
        double spinLong =0., spinLat = 0.;
×
698

699
        // Getting coordinates (in radians) of position of the center of the screen
700
        switch (getCurrentCoordinateSystem())
×
701
        {
702
                case equatorialJ2000:
×
703
                        StelUtils::rectToSphe(&spinLong, &spinLat, centerPos);
×
704
                        break;
×
705
                case equatorial:
×
706
                        StelUtils::rectToSphe(&spinLong, &spinLat, core->j2000ToEquinoxEqu(centerPos, StelCore::RefractionOff));
×
707
                        break;
×
708
                case galactic:
×
709
                        StelUtils::rectToSphe(&spinLong, &spinLat, core->j2000ToGalactic(centerPos));
×
710
                        break;
×
711
                case supergalactic:
×
712
                        StelUtils::rectToSphe(&spinLong, &spinLat, core->j2000ToSupergalactic(centerPos));
×
713
                        break;
×
714
                case horizontal:
×
715
                {
716
                        StelUtils::rectToSphe(&spinLong, &spinLat, core->j2000ToAltAz(centerPos, StelCore::RefractionAuto));
×
717
                        spinLong = 3.*M_PI - spinLong; // N is zero, E is 90 degrees
×
718
                        if (StelApp::getInstance().getFlagSouthAzimuthUsage())
×
719
                                spinLong+=M_PI;
×
720
                        spinLong=StelUtils::fmodpos(spinLong, 2.*M_PI);
×
721
                        break;
×
722
                }
723
                case eclipticJ2000:
×
724
                {
725
                        double lambda, beta;
726
                        StelUtils::rectToSphe(&spinLong, &spinLat, centerPos);
×
727
                        StelUtils::equToEcl(spinLong, spinLat, GETSTELMODULE(SolarSystem)->getEarth()->getRotObliquity(2451545.0), &lambda, &beta);
×
728
                        if (lambda<0) lambda+=2.0*M_PI;
×
729
                        spinLong = lambda;
×
730
                        spinLat = beta;
×
731
                        break;
×
732
                }
733
                case ecliptic:
×
734
                {
735
                        double lambda, beta;
736
                        StelUtils::rectToSphe(&spinLong, &spinLat, core->j2000ToEquinoxEqu(centerPos, StelCore::RefractionOff));
×
737
                        StelUtils::equToEcl(spinLong, spinLat, GETSTELMODULE(SolarSystem)->getEarth()->getRotObliquity(core->getJDE()), &lambda, &beta);
×
738
                        if (lambda<0) lambda+=2.0*M_PI;
×
739
                        spinLong = lambda;
×
740
                        spinLat = beta;
×
741
                        break;
×
742
                }
743
        }
744

745
        // Block spinbox signals locally, just until end of method.
746
        const QSignalBlocker blockX(ui->AxisXSpinBox);
×
747
        const QSignalBlocker blockY(ui->AxisYSpinBox);
×
748

749
        // set coordinates in spinboxes
750
        ui->AxisXSpinBox->setRadians(spinLong);
×
751
        ui->AxisYSpinBox->setRadians(spinLat);
×
752
}
×
753

754
void SearchDialog::manualPositionChanged()
×
755
{
756
        searchListModel->clearValues();
×
757
        StelCore* core = StelApp::getInstance().getCore();
×
758
        StelMovementMgr* mvmgr = GETSTELMODULE(StelMovementMgr);        
×
759
        Vec3d pos;        
×
760
        double spinLong=ui->AxisXSpinBox->valueRadians();
×
761
        double spinLat=ui->AxisYSpinBox->valueRadians();
×
762

763
        // Since 0.15: proper handling of aimUp vector. This does not depend on the searched coordinate system, but on the MovementManager's C.S.
764
        // 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.
765
        // aimUp depends on MovementMgr::MountMode mvmgr->mountMode!
766
        mvmgr->setViewUpVector(Vec3d(0., 0., 1.));
×
767
        Vec3d aimUp = mvmgr->getViewUpVectorJ2000();
×
768
        StelMovementMgr::MountMode mountMode=mvmgr->getMountMode();
×
769

770
        switch (getCurrentCoordinateSystem())
×
771
        {
772
                case equatorialJ2000:
×
773
                {
774
                        StelUtils::spheToRect(spinLong, spinLat, pos);
×
775
                        if ( (mountMode==StelMovementMgr::MountEquinoxEquatorial) && (fabs(spinLat)> (0.9*M_PI_2)) )
×
776
                        {
777
                                // make up vector more stable.
778
                                // Strictly mount should be in a new J2000 mode, but this here also stabilizes searching J2000 coordinates.
779
                                mvmgr->setViewUpVector(Vec3d(-cos(spinLong), -sin(spinLong), 0.) * (spinLat>0. ? 1. : -1. ));
×
780
                                aimUp=mvmgr->getViewUpVectorJ2000();
×
781
                        }
782
                        break;
×
783
                }
784
                case equatorial:
×
785
                {
786
                        StelUtils::spheToRect(spinLong, spinLat, pos);
×
787
                        pos = core->equinoxEquToJ2000(pos, StelCore::RefractionOff);
×
788

789
                        if ( (mountMode==StelMovementMgr::MountEquinoxEquatorial) && (fabs(spinLat)> (0.9*M_PI_2)) )
×
790
                        {
791
                                // make up vector more stable.
792
                                mvmgr->setViewUpVector(Vec3d(-cos(spinLong), -sin(spinLong), 0.) * (spinLat>0. ? 1. : -1. ));
×
793
                                aimUp=mvmgr->getViewUpVectorJ2000();
×
794
                        }
795
                        break;
×
796
                }
797
                case horizontal:
×
798
                {
799
                        double cx;
800
                        cx = 3.*M_PI - spinLong; // N is zero, E is 90 degrees
×
801
                        if (StelApp::getInstance().getFlagSouthAzimuthUsage())
×
802
                                cx -= M_PI;
×
803
                        StelUtils::spheToRect(cx, spinLat, pos);
×
804
                        pos = core->altAzToJ2000(pos, StelCore::RefractionOff);
×
805
                        core->setTimeRate(0.);
×
806

807
                        if ( (mountMode==StelMovementMgr::MountAltAzimuthal) && (fabs(spinLat)> (0.9*M_PI_2)) )
×
808
                        {
809
                                // make up vector more stable.
810
                                mvmgr->setViewUpVector(Vec3d(-cos(cx), -sin(cx), 0.) * (spinLat>0. ? 1. : -1. ));
×
811
                                aimUp=mvmgr->getViewUpVectorJ2000();
×
812
                        }
813
                        break;
×
814
                }
815
                case galactic:
×
816
                {
817
                        StelUtils::spheToRect(spinLong, spinLat, pos);
×
818
                        pos = core->galacticToJ2000(pos);
×
819
                        if ( (mountMode==StelMovementMgr::MountGalactic) && (fabs(spinLat)> (0.9*M_PI_2)) )
×
820
                        {
821
                                // make up vector more stable.
822
                                mvmgr->setViewUpVector(Vec3d(-cos(spinLong), -sin(spinLong), 0.) * (spinLat>0. ? 1. : -1. ));
×
823
                                aimUp=mvmgr->getViewUpVectorJ2000();
×
824
                        }
825
                        break;
×
826
                }
827
                case supergalactic:
×
828
                {
829
                        StelUtils::spheToRect(spinLong, spinLat, pos);
×
830
                        pos = core->supergalacticToJ2000(pos);
×
831
                        if ( (mountMode==StelMovementMgr::MountSupergalactic) && (fabs(spinLat)> (0.9*M_PI_2)) )
×
832
                        {
833
                                // make up vector more stable.
834
                                mvmgr->setViewUpVector(Vec3d(-cos(spinLong), -sin(spinLong), 0.) * (spinLat>0. ? 1. : -1. ));
×
835
                                aimUp=mvmgr->getViewUpVectorJ2000();
×
836
                        }
837
                        break;
×
838
                }
839
                case eclipticJ2000:
×
840
                {
841
                        double ra, dec;
842
                        StelUtils::eclToEqu(spinLong, spinLat, GETSTELMODULE(SolarSystem)->getEarth()->getRotObliquity(2451545.0), &ra, &dec);
×
843
                        StelUtils::spheToRect(ra, dec, pos);
×
844
                        break;
×
845
                }
846
                case ecliptic:
×
847
                {
848
                        double ra, dec;
849
                        StelUtils::eclToEqu(spinLong, spinLat, GETSTELMODULE(SolarSystem)->getEarth()->getRotObliquity(core->getJDE()), &ra, &dec);
×
850
                        StelUtils::spheToRect(ra, dec, pos);
×
851
                        pos = core->equinoxEquToJ2000(pos, StelCore::RefractionOff);
×
852
                        break;
×
853
                }
854
        }
855
        mvmgr->setFlagTracking(false);
×
856
        mvmgr->moveToJ2000(pos, aimUp, mvmgr->getAutoMoveDuration());
×
857
        mvmgr->setFlagLockEquPos(useLockPosition);
×
858
}
×
859

860
void SearchDialog::onSearchTextChanged(const QString& text)
×
861
{
862
        clearSimbadText(StelModule::ReplaceSelection);
×
863
        // This block needs to go before the trimmedText.isEmpty() or the SIMBAD result does not
864
        // get properly cleared.
865
        if (useSimbad)
×
866
        {
867
                if (simbadReply)
×
868
                {
869
                        disconnect(simbadReply, SIGNAL(statusChanged()), this, SLOT(onSimbadStatusChanged()));
×
870
                        delete simbadReply;
×
871
                        simbadReply=nullptr;
×
872
                }
873
                simbadResults.clear();
×
874
        }
875

876
        // Use to adjust matches to be within range of maxNbItem
877
        int maxNbItem;
878
        QString trimmedText = text.trimmed();
×
879
        if (trimmedText.isEmpty())
×
880
        {
881
                searchListModel->clearValues();
×
882

883
                maxNbItem = recentObjectSearchesData.maxSize;
×
884
                // Auto display recent searches
885
                QStringList recentMatches = listMatchingRecentObjects(trimmedText, maxNbItem, useStartOfWords);
×
886
                resetSearchResultDisplay(recentMatches, recentMatches);
×
887

888
                ui->simbadStatusLabel->setText("");
×
889
                ui->simbadCooStatusLabel->setText("");
×
890
                setPushButtonGotoSearch();
×
891
        }
×
892
        else
893
        {
894
                if (useSimbad)
×
895
                {
896
                        simbadReply = simbadSearcher->lookup(simbadServerUrl, trimmedText, 4);
×
897
                        onSimbadStatusChanged();
×
898
                        connect(simbadReply, SIGNAL(statusChanged()), this, SLOT(onSimbadStatusChanged()));
×
899
                }
900

901
                // Get possible objects
902
                QStringList matches;
×
903
                QStringList recentMatches;
×
904
                QStringList allMatches;
×
905

906
                QString greekText = substituteGreek(trimmedText);
×
907

908
                int trimmedTextMaxNbItem = 50;
×
909
                int greekTextMaxMbItem = 0;
×
910

911
                if(greekText != trimmedText)
×
912
                {
913
                        trimmedTextMaxNbItem = 50;
×
914
                        greekTextMaxMbItem = 18;
×
915

916
                        // Get recent matches
917
                        // trimmedText
918
                        recentMatches = listMatchingRecentObjects(trimmedText, trimmedTextMaxNbItem, useStartOfWords);
×
919
                        // greekText
920
                        recentMatches += listMatchingRecentObjects(greekText, (greekTextMaxMbItem - recentMatches.size()), useStartOfWords);
×
921

922
                        // Get rest of matches
923
                        // trimmedText
924
                        matches = objectMgr->listMatchingObjects(trimmedText, trimmedTextMaxNbItem, useStartOfWords);
×
925
                        // greekText
926
                        matches += objectMgr->listMatchingObjects(greekText, (greekTextMaxMbItem - matches.size()), useStartOfWords);
×
927
                }
928
                else
929
                {
930
                        trimmedTextMaxNbItem = 50;
×
931

932
                        // Get recent matches
933
                        recentMatches = listMatchingRecentObjects(trimmedText, trimmedTextMaxNbItem, useStartOfWords);
×
934

935
                        // Get rest of matches
936
                        matches  = objectMgr->listMatchingObjects(trimmedText, trimmedTextMaxNbItem, useStartOfWords);
×
937
                }
938
                // Check in case either number changes since they were
939
                // hard coded
940
                maxNbItem  = qMax(greekTextMaxMbItem, trimmedTextMaxNbItem);
×
941

942
                // Clean up matches
943
                adjustMatchesResult(allMatches, recentMatches, matches, maxNbItem);
×
944

945
                // Updates values
946
                resetSearchResultDisplay(allMatches, recentMatches);
×
947

948
                // Update push button enabled state
949
                setPushButtonGotoSearch();
×
950
        }
×
951

952
        // Goto object when clicking in list
953
        connect(ui->searchListView, SIGNAL(clicked(const QModelIndex&)), this, SLOT(gotoObject(const QModelIndex&)), Qt::UniqueConnection);
×
954
        connect(ui->searchListView, SIGNAL(activated(const QModelIndex&)), this, SLOT(gotoObject(const QModelIndex&)), Qt::UniqueConnection);
×
955
}
×
956

957
void SearchDialog::updateRecentSearchList(const QString &nameI18n)
×
958
{
959
        if(nameI18n.isEmpty())
×
960
                return;
×
961

962
        // Prepend & remove duplicates
963
        recentObjectSearchesData.recentList.prepend(nameI18n);
×
964
        recentObjectSearchesData.recentList.removeDuplicates();
×
965

966
        adjustRecentList(recentObjectSearchesData.maxSize);
×
967

968
        // Auto display recent searches
969
        QStringList recentMatches = listMatchingRecentObjects("", recentObjectSearchesData.maxSize, useStartOfWords);
×
970
        resetSearchResultDisplay(recentMatches, recentMatches);
×
971
}
×
972

973
void SearchDialog::adjustRecentList(int maxSize)
×
974
{        
975
        // Check if max size was updated recently
976
        maxSize = (maxSize >= 0) ? maxSize : recentObjectSearchesData.maxSize;
×
977
        recentObjectSearchesData.maxSize = maxSize;
×
978

979
        // Max amount of saved values "allowed"
980
        int spinBoxMaxSize = ui->recentSearchSizeSpinBox->maximum();
×
981

982
        // Only removing old searches if the list grows larger than the largest
983
        // "allowed" size (to retain data in case the user switches from
984
        // high to low size)
985
        if( recentObjectSearchesData.recentList.size() > spinBoxMaxSize)
×
986
                recentObjectSearchesData.recentList = recentObjectSearchesData.recentList.mid(0, spinBoxMaxSize);
×
987
}
×
988

989
void SearchDialog::adjustMatchesResult(QStringList &allMatches, QStringList& recentMatches, QStringList& matches, int maxNbItem)
×
990
{
991
        int tempSize;
992
        QStringList tempMatches; // unsorted matches use for calculation
×
993
        // not displaying
994

995
        // remove possible duplicates from completion list
996
        matches.removeDuplicates();
×
997

998
        matches.sort(Qt::CaseInsensitive);
×
999
        // objects with short names should be searched first
1000
        // examples: Moon, Hydra (moon); Jupiter, Ghost of Jupiter
1001
        stringLengthCompare comparator;
1002
        std::sort(matches.begin(), matches.end(), comparator);
×
1003

1004
        // Adjust recent matches to preferred max size
1005
        recentMatches = recentMatches.mid(0, recentObjectSearchesData.maxSize);
×
1006

1007
        // Find total size of both matches
1008
        tempMatches << recentMatches << matches; // unsorted
×
1009
        tempMatches.removeDuplicates();
×
1010
        tempSize = tempMatches.size();
×
1011

1012
        // Adjust match size to be within range
1013
        if(tempSize>maxNbItem)
×
1014
        {
1015
                int i = tempSize - maxNbItem;
×
1016
                matches = matches.mid(0, matches.size() - i);
×
1017
        }
1018

1019
        // Combine list: ordered by recent searches then relevance
1020
        allMatches << recentMatches << matches;
×
1021

1022
        // Remove possible duplicates from both lists
1023
        allMatches.removeDuplicates();
×
1024
}
×
1025

1026

1027
void SearchDialog::resetSearchResultDisplay(QStringList allMatches,
×
1028
                                               QStringList recentMatches)
1029
{
1030
        // Updates values
1031
        searchListModel->appendValues(allMatches);
×
1032
        searchListModel->appendRecentValues(recentMatches);
×
1033

1034
        // Update display
1035
        searchListModel->setValues(allMatches, recentMatches);
×
1036
        searchListModel->selectFirst();
×
1037

1038
        // Update highlight to top
1039
        ui->searchListView->scrollToTop();
×
1040
        int row = searchListModel->getSelectedIdx();
×
1041
        ui->searchListView->setCurrentIndex(searchListModel->index(row));
×
1042

1043
        // Enable clear data button
1044
        setRecentSearchClearDataPushButton();
×
1045
}
×
1046

1047
void SearchDialog::setPushButtonGotoSearch()
×
1048
{
1049
        // Empty search and empty recently search object list
1050
        if (searchListModel->isEmpty() && (recentObjectSearchesData.recentList.size() == 0))
×
1051
                ui->pushButtonGotoSearchSkyObject->setEnabled(false); // Do not enable search button
×
1052
        else
1053
                ui->pushButtonGotoSearchSkyObject->setEnabled(true); // Do enable search  button
×
1054
}
×
1055

1056
void SearchDialog::loadRecentSearches()
×
1057
{
1058
        QVariantMap map;
×
1059
        QFile jsonFile(recentObjectSearchesJsonPath);
×
1060
        if(!jsonFile.open(QIODevice::ReadOnly))
×
1061
        {
1062
                qWarning() << "[Search] Can not open data file for recent searches"
×
1063
                           << QDir::toNativeSeparators(recentObjectSearchesJsonPath);
×
1064

1065
                // Use default value for recent search size
1066
                setRecentSearchSize(ui->recentSearchSizeSpinBox->value());
×
1067
        }
1068
        else
1069
        {
1070
                try
1071
                {
1072
                        int readMaxSize;
1073

1074
                        map = StelJsonParser::parse(jsonFile.readAll()).toMap();
×
1075
                        jsonFile.close();
×
1076

1077
                        QVariantMap recentSearchData = map.value("recentObjectSearches").toMap();
×
1078

1079
                        // Get user's maxSize data (if possible)
1080
                        readMaxSize = recentSearchData.value("maxSize").toInt();
×
1081
                         // Non-negative size only
1082
                        recentObjectSearchesData.maxSize = (readMaxSize >= 0) ? readMaxSize : recentObjectSearchesData.maxSize;
×
1083

1084
                        // Update dialog size to match user's preference
1085
                        ui->recentSearchSizeSpinBox->setValue(recentObjectSearchesData.maxSize);
×
1086

1087
                        // Get user's recentList data (if possible)
1088
                        recentObjectSearchesData.recentList = recentSearchData.value("recentList").toStringList();
×
1089
                }
×
1090
                catch (std::runtime_error &e)
×
1091
                {
1092
                        qWarning() << "[Search] File format is Wrong! Error:"
×
1093
                                   << e.what();
×
1094
                        return;
×
1095
                }
×
1096
        }
1097
}
×
1098

1099
void SearchDialog::saveRecentSearches()
×
1100
{
1101
        if(recentObjectSearchesJsonPath.isEmpty())
×
1102
        {
1103
                qWarning() << "[Search] Error in saving recent object searches";
×
1104
                return;
×
1105
        }
1106

1107
        QFile jsonFile(recentObjectSearchesJsonPath);
×
1108
        if(!jsonFile.open(QFile::WriteOnly | QFile::Text))
×
1109
        {
1110
                qWarning() << "[Search] Recent search could not be save. A file can not be open for writing:"
×
1111
                           << QDir::toNativeSeparators(recentObjectSearchesJsonPath);
×
1112
                return;
×
1113
        }
1114

1115
        QVariantMap rslDataList;
×
1116
        rslDataList.insert("maxSize", recentObjectSearchesData.maxSize);
×
1117
        rslDataList.insert("recentList", recentObjectSearchesData.recentList);
×
1118
        
1119
        QVariantMap rsList;
×
1120
        rsList.insert("recentObjectSearches", rslDataList);
×
1121

1122
        // Convert the tree to JSON
1123
        StelJsonParser::write(rsList, &jsonFile);
×
1124
        jsonFile.flush();
×
1125
        jsonFile.close();
×
1126
}
×
1127

1128
QStringList SearchDialog::listMatchingRecentObjects(const QString& objPrefix, int maxNbItem, bool useStartOfWords) const
×
1129
{
1130
        QStringList result;
×
1131

1132
        if(maxNbItem <= 0)
×
1133
                return result;
×
1134

1135
        // For all recent objects:
1136
        for (int i = 0; i < recentObjectSearchesData.recentList.size(); i++)
×
1137
        {
1138
                bool toAppend = useStartOfWords ? recentObjectSearchesData.recentList[i].startsWith(objPrefix, Qt::CaseInsensitive)
×
1139
                                                : recentObjectSearchesData.recentList[i].contains(objPrefix, Qt::CaseInsensitive);
×
1140

1141
                if(toAppend)
×
1142
                        result.append(recentObjectSearchesData.recentList[i]);
×
1143

1144
                if (result.size() >= maxNbItem)
×
1145
                        break;
×
1146
        }
1147

1148
        if (useLengthSorting)
×
1149
        {
1150
                stringLengthCompare comparator;
1151
                std::sort(result.begin(), result.end(), comparator);
×
1152
        }
1153

1154
        return result;
×
1155
}
×
1156

1157

1158
void SearchDialog::lookupCoordinates()
×
1159
{
1160
        if (!useSimbad)
×
1161
                return;
×
1162

1163
        StelCore * core=StelApp::getInstance().getCore();
×
1164
        const QList<StelObjectP>& sel=GETSTELMODULE(StelObjectMgr)->getSelectedObject();
×
1165
        if (sel.length()==0)
×
1166
                return;
×
1167

1168
        Vec3d coords=sel.at(0)->getJ2000EquatorialPos(core);
×
1169

1170
        simbadReply = simbadSearcher->lookupCoords(simbadServerUrl, coords, getSimbadQueryCount(), 500,
×
1171
                                                   getSimbadQueryDist(), getSimbadGetsIds(), getSimbadGetsTypes(),
×
1172
                                                   getSimbadGetsSpec(), getSimbadGetsMorpho(), getSimbadGetsDims());
×
1173
        onSimbadStatusChanged();
×
1174
        connect(simbadReply, SIGNAL(statusChanged()), this, SLOT(onSimbadStatusChanged()));
×
1175
}
1176

1177
void SearchDialog::clearSimbadText(StelModule::StelModuleSelectAction)
×
1178
{
1179
        ui->simbadCooResultsTextBrowser->clear();
×
1180
}
×
1181

1182
// Called when the current simbad query status changes
1183
void SearchDialog::onSimbadStatusChanged()
×
1184
{
1185
        Q_ASSERT(simbadReply);
×
1186
        int index = ui->tabWidget->currentIndex();
×
1187
        QString info;
×
1188
        if (simbadReply->getCurrentStatus()==SimbadLookupReply::SimbadLookupErrorOccured)
×
1189
        {
1190
                info = QString("%1: %2").arg(q_("Simbad Lookup Error"), simbadReply->getErrorString());
×
1191
                index==1 ? ui->simbadCooStatusLabel->setText(info) : ui->simbadStatusLabel->setText(info);
×
1192
                setPushButtonGotoSearch();
×
1193
                ui->simbadCooResultsTextBrowser->clear();
×
1194
        }
1195
        else
1196
        {
1197
                info = QString("%1: %2").arg(q_("Simbad Lookup"), simbadReply->getCurrentStatusString());
×
1198
                index==1 ? ui->simbadCooStatusLabel->setText(info) : ui->simbadStatusLabel->setText(info);
×
1199
                // Query not over, don't disable button
1200
                ui->pushButtonGotoSearchSkyObject->setEnabled(true);
×
1201
        }
1202

1203
        if (simbadReply->getCurrentStatus()==SimbadLookupReply::SimbadLookupFinished)
×
1204
        {
1205
                simbadResults = simbadReply->getResults();
×
1206
                searchListModel->appendValues(simbadResults.keys());
×
1207
                // Update push button enabled state
1208
                setPushButtonGotoSearch();
×
1209
        }
1210

1211
        if (simbadReply->getCurrentStatus()==SimbadLookupReply::SimbadCoordinateLookupFinished)
×
1212
        {
1213
                QString ret = simbadReply->getResult();
×
1214
                ui->simbadCooResultsTextBrowser->setText(ret);
×
1215
        }
×
1216

1217
        if (simbadReply->getCurrentStatus()!=SimbadLookupReply::SimbadLookupQuerying)
×
1218
        {
1219
                disconnect(simbadReply, SIGNAL(statusChanged()), this, SLOT(onSimbadStatusChanged()));
×
1220
                delete simbadReply;
×
1221
                simbadReply=nullptr;
×
1222

1223
                // Update push button enabled state
1224
                setPushButtonGotoSearch();
×
1225
        }
1226
}
×
1227

1228
void SearchDialog::greekLetterClicked()
×
1229
{
1230
        QPushButton *sender = reinterpret_cast<QPushButton *>(this->sender());
×
1231
        QLineEdit* sso = ui->lineEditSearchSkyObject;
×
1232
        QString text;
×
1233
        if (sender)
×
1234
        {
1235
                shiftPressed ? text = sender->text().toUpper() : text = sender->text();
×
1236
                if (flagHasSelectedText)
×
1237
                {
1238
                        sso->setText(text);
×
1239
                        flagHasSelectedText = false;
×
1240
                }
1241
                else
1242
                        sso->setText(sso->text() + text);
×
1243
        }
1244
        sso->setFocus();
×
1245
}
×
1246

1247
void SearchDialog::gotoObject()
×
1248
{
1249
        gotoObject(searchListModel->getSelected());
×
1250
}
×
1251

1252
void SearchDialog::gotoObject(const QString &nameI18n)
×
1253
{
1254
        if (nameI18n.isEmpty())
×
1255
                return;
×
1256

1257
        // Save recent search list
1258
        updateRecentSearchList(nameI18n);
×
1259
        saveRecentSearches();
×
1260

1261
        StelMovementMgr* mvmgr = GETSTELMODULE(StelMovementMgr);
×
1262
        if (simbadResults.contains(nameI18n))
×
1263
        {
1264
                if (objectMgr->findAndSelect(nameI18n))
×
1265
                {
1266
                        const QList<StelObjectP> newSelected = objectMgr->getSelectedObject();
×
1267
                        if (!newSelected.empty())
×
1268
                        {
1269
                                if (useAutoClosing)
×
1270
                                        close();
×
1271
                                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
×
1272

1273
                                // Can't point to home planet
1274
                                if (newSelected[0]->getEnglishName()!=StelApp::getInstance().getCore()->getCurrentLocation().planetName)
×
1275
                                {
1276
                                        mvmgr->moveToObject(newSelected[0], mvmgr->getAutoMoveDuration());
×
1277
                                        mvmgr->setFlagTracking(true);
×
1278
                                }
1279
                                else
1280
                                        GETSTELMODULE(StelObjectMgr)->unSelect();
×
1281
                        }
1282
                }
×
1283
                else
1284
                {
1285
                        if (useAutoClosing)
×
1286
                                close();
×
1287
                        GETSTELMODULE(CustomObjectMgr)->addPersistentObject(nameI18n, simbadResults[nameI18n]);
×
1288
                        ui->lineEditSearchSkyObject->clear();
×
1289
                        searchListModel->clearValues();
×
1290
                        if (objectMgr->findAndSelect(nameI18n))
×
1291
                        {
1292
                                const QList<StelObjectP> newSelected = objectMgr->getSelectedObject();
×
1293
                                // Can't point to home planet
1294
                                if (newSelected[0]->getEnglishName()!=StelApp::getInstance().getCore()->getCurrentLocation().planetName)
×
1295
                                {
1296
                                        mvmgr->moveToObject(newSelected[0], mvmgr->getAutoMoveDuration());
×
1297
                                        mvmgr->setFlagTracking(true);
×
1298
                                }
1299
                                else
1300
                                        GETSTELMODULE(StelObjectMgr)->unSelect();
×
1301
                        }
×
1302
                }
1303
        }
1304
        else if (objectMgr->findAndSelectI18n(nameI18n) || objectMgr->findAndSelect(nameI18n))
×
1305
        {
1306
                const QList<StelObjectP> newSelected = objectMgr->getSelectedObject();
×
1307
                if (!newSelected.empty())
×
1308
                {
1309
                        if (useAutoClosing)
×
1310
                                close();
×
1311
                        ui->lineEditSearchSkyObject->clear();
×
1312

1313
                        // Can't point to home planet
1314
                        if (newSelected[0]->getEnglishName()!=StelApp::getInstance().getCore()->getCurrentLocation().planetName)
×
1315
                        {
1316
                                mvmgr->moveToObject(newSelected[0], mvmgr->getAutoMoveDuration());
×
1317
                                mvmgr->setFlagTracking(true);
×
1318
                        }
1319
                        else
1320
                                GETSTELMODULE(StelObjectMgr)->unSelect();
×
1321
                }
1322
        }
×
1323
        simbadResults.clear();
×
1324
}
1325

1326
void SearchDialog::gotoObject(const QString &nameI18n, const QString &objType)
×
1327
{
1328
        if (nameI18n.isEmpty())
×
1329
                return;
×
1330

1331
        StelMovementMgr* mvmgr = GETSTELMODULE(StelMovementMgr);
×
1332
        if (objectMgr->findAndSelectI18n(nameI18n, objType) || objectMgr->findAndSelect(nameI18n, objType))
×
1333
        {
1334
                const QList<StelObjectP> newSelected = objectMgr->getSelectedObject();
×
1335
                if (!newSelected.empty())
×
1336
                {
1337
                        if (useAutoClosing)
×
1338
                                close();
×
1339
                        ui->lineEditSearchSkyObject->clear();
×
1340
                        
1341
                        // Can't point to home planet
1342
                        if (newSelected[0]->getEnglishName()!=StelApp::getInstance().getCore()->getCurrentLocation().planetName)
×
1343
                        {
1344
                                mvmgr->moveToObject(newSelected[0], mvmgr->getAutoMoveDuration());
×
1345
                                mvmgr->setFlagTracking(true);
×
1346
                        }
1347
                        else
1348
                                GETSTELMODULE(StelObjectMgr)->unSelect();
×
1349
                }
1350
        }
×
1351
}
1352

1353
void SearchDialog::gotoObject(const QModelIndex &modelIndex)
×
1354
{
1355
        gotoObject(modelIndex.model()->data(modelIndex, Qt::DisplayRole).toString());
×
1356
}
×
1357

1358
void SearchDialog::gotoObjectWithType(const QModelIndex &modelIndex)
×
1359
{
1360
        QString objType, objClass = ui->objectTypeComboBox->currentData(Qt::UserRole).toString();
×
1361
        if (objClass.contains(":"))
×
1362
        {
1363
                #if (QT_VERSION>=QT_VERSION_CHECK(5, 14, 0))
1364
                QStringList list = objClass.split(":", Qt::SkipEmptyParts);
×
1365
                #else
1366
                QStringList list = objClass.split(":", QString::SkipEmptyParts);
1367
                #endif
1368
                objType = list.at(0);
×
1369
        }
×
1370
        else
1371
                objType = objClass;
×
1372

1373
        objType.replace("Mgr","");
×
1374
        objType.replace("SolarSystem","Planet");
×
1375
        objType.replace("Nomenclature","NomenclatureItem");
×
1376
        // plug-ins
1377
        objType.replace("Supernovae","Supernova");
×
1378
        objType.replace("Satellites","Satellite");
×
1379
        objType.replace("Novae","Nova");
×
1380
        objType.replace("Exoplanets","Exoplanet");
×
1381
        objType.replace("Pulsars","Pulsar");
×
1382
        objType.replace("Quasars","Quasar");
×
1383
        objType.replace("MeteorShowers","MeteorShower");
×
1384

1385
        gotoObject(modelIndex.model()->data(modelIndex, Qt::DisplayRole).toString(), objType);
×
1386
}
×
1387

1388
void SearchDialog::searchListClear()
×
1389
{
1390
        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
×
1391
}
×
1392

1393
bool SearchDialog::eventFilter(QObject*, QEvent *event)
×
1394
{
1395
        if (event->type() == QEvent::KeyPress)
×
1396
        {
1397
                QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
×
1398

1399
                if (keyEvent->key() == Qt::Key_Shift)
×
1400
                {
1401
                        shiftPressed = true;
×
1402
                        event->accept();
×
1403
                        return true;
×
1404
                }
1405
        }
1406
        if (event->type() == QEvent::KeyRelease)
×
1407
        {
1408
                QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
×
1409

1410
                if (keyEvent->key() == Qt::Key_Tab || keyEvent->key() == Qt::Key_Down)
×
1411
                {
1412
                        searchListModel->selectNext();
×
1413
                        int row = searchListModel->getSelectedIdx();
×
1414
                        ui->searchListView->scrollTo(searchListModel->index(row));
×
1415
                        ui->searchListView->setCurrentIndex(searchListModel->index(row));
×
1416
                        event->accept();
×
1417
                        return true;
×
1418
                }
1419
                if (keyEvent->key() == Qt::Key_Up)
×
1420
                {
1421
                        searchListModel->selectPrevious();
×
1422
                        int row = searchListModel->getSelectedIdx();
×
1423
                        ui->searchListView->scrollTo(searchListModel->index(row));
×
1424
                        ui->searchListView->setCurrentIndex(searchListModel->index(row));
×
1425
                        event->accept();
×
1426
                        return true;
×
1427
                }
1428
                if (keyEvent->key() == Qt::Key_Shift)
×
1429
                {
1430
                        shiftPressed = false;
×
1431
                        event->accept();
×
1432
                        return true;
×
1433
                }
1434
        }
1435
        if (event->type() == QEvent::Show)
×
1436
        {
1437
                if (!extSearchText.isEmpty())
×
1438
                {
1439
                        ui->lineEditSearchSkyObject->setText(extSearchText);
×
1440
                        ui->lineEditSearchSkyObject->selectAll();
×
1441
                        extSearchText.clear();
×
1442
                }
1443
        }
1444
        return false;
×
1445
}
1446

1447
QString SearchDialog::substituteGreek(const QString& keyString)
×
1448
{
1449
        if (!keyString.contains(' '))
×
1450
                return getGreekLetterByName(keyString);
×
1451
        else
1452
        {
1453
                #if (QT_VERSION>=QT_VERSION_CHECK(5, 14, 0))
1454
                QStringList nameComponents = keyString.split(" ", Qt::SkipEmptyParts);
×
1455
                #else
1456
                QStringList nameComponents = keyString.split(" ", QString::SkipEmptyParts);
1457
                #endif
1458
                if(!nameComponents.empty())
×
1459
                        nameComponents[0] = getGreekLetterByName(nameComponents[0]);
×
1460
                return nameComponents.join(" ");
×
1461
        }
×
1462
}
1463

1464
QString SearchDialog::getGreekLetterByName(const QString& potentialGreekLetterName)
×
1465
{
1466
        if(staticData.greekLetters.contains(potentialGreekLetterName))
×
1467
                return staticData.greekLetters[potentialGreekLetterName];
×
1468

1469
        // There can be indices (e.g. "α1 Cen" instead of "α Cen A"), so strip
1470
        // any trailing digit.
1471
        int lastCharacterIndex = potentialGreekLetterName.length()-1;
×
1472
        if(potentialGreekLetterName.at(lastCharacterIndex).isDigit())
×
1473
        {
1474
                QChar digit = potentialGreekLetterName.at(lastCharacterIndex);
×
1475
                QString name = potentialGreekLetterName.left(lastCharacterIndex);
×
1476
                if(staticData.greekLetters.contains(name))
×
1477
                        return staticData.greekLetters[name] + digit;
×
1478
        }
×
1479

1480
        return potentialGreekLetterName;
×
1481
}
1482

1483
void SearchDialog::populateSimbadServerList()
×
1484
{
1485
        Q_ASSERT(ui->serverListComboBox);
×
1486

1487
        QComboBox* servers = ui->serverListComboBox;
×
1488
        //Save the current selection to be restored later
1489
        servers->blockSignals(true);
×
1490
        int index = servers->currentIndex();
×
1491
        QVariant selectedUrl = servers->itemData(index);
×
1492
        servers->clear();
×
1493
        //For each server, display the localized description and store the URL as user data.
1494
        servers->addItem(q_("University of Strasbourg (France)"), DEF_SIMBAD_URL);
×
1495
        servers->addItem(q_("Harvard-Smithsonian Center for Astrophysics (USA)"), "https://simbad.cfa.harvard.edu/");
×
1496
        servers->addItem(q_("Strasbourg astronomical Data Center (France)"), "https://simbad.cds.unistra.fr/");
×
1497

1498
        //Restore the selection
1499
        index = servers->findData(selectedUrl, Qt::UserRole, Qt::MatchCaseSensitive);
×
1500
        servers->setCurrentIndex(index);
×
1501
        servers->model()->sort(0);
×
1502
        servers->blockSignals(false);
×
1503
}
×
1504

1505
void SearchDialog::setRecentSearchSize(int maxSize)
×
1506
{
1507
        adjustRecentList(maxSize);
×
1508
        saveRecentSearches();
×
1509
        conf->setValue("search/recentSearchSize", recentObjectSearchesData.maxSize);
×
1510
}
×
1511

1512
void SearchDialog::selectSimbadServer(int index)
×
1513
{
1514
        index < 0 ? simbadServerUrl = DEF_SIMBAD_URL : simbadServerUrl = ui->serverListComboBox->itemData(index).toString();
×
1515
        conf->setValue("search/simbad_server_url", simbadServerUrl);
×
1516
}
×
1517

1518
void SearchDialog::updateListView(int index)
×
1519
{
1520
        QString moduleId = ui->objectTypeComboBox->itemData(index).toString();
×
1521
        bool englishNames = ui->searchInEnglishCheckBox->isChecked();
×
1522
        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
×
1523
        ui->objectsListView->blockSignals(true);
×
1524
        ui->objectsListView->reset();
×
1525
        listModel->setStringList(objectMgr->listAllModuleObjects(moduleId, englishNames));
×
1526
        proxyModel->setSourceModel(listModel);
×
1527
        proxyModel->sort(0, Qt::AscendingOrder);
×
1528
        ui->objectsListView->blockSignals(false);
×
1529
        //bugfix: prevent multiple connections, which seems to have happened before
1530
        connect(ui->objectsListView, SIGNAL(clicked(const QModelIndex&)), this, SLOT(gotoObjectWithType(const QModelIndex&)), Qt::UniqueConnection);
×
1531
}
×
1532

1533
void SearchDialog::updateListTab()
×
1534
{
1535
        QVariant selectedObjectId;
×
1536
        QVariant defaultObjectId = QVariant("ConstellationMgr"); // Let's enable "Constellations" by default!
×
1537
        QComboBox* objects = ui->objectTypeComboBox;
×
1538
        int index = objects->currentIndex();
×
1539
        selectedObjectId = (index < 0) ? defaultObjectId : objects->itemData(index, Qt::UserRole);
×
1540

1541
        if (StelApp::getInstance().getLocaleMgr().getAppLanguage().startsWith("en"))
×
1542
                ui->searchInEnglishCheckBox->hide(); // hide "names in English" checkbox
×
1543
        else
1544
                ui->searchInEnglishCheckBox->show();
×
1545
        objects->blockSignals(true);
×
1546
        objects->clear();
×
1547
        QMap<QString, QString> modulesMap = objectMgr->objectModulesMap();
×
1548
        for (auto it = modulesMap.begin(); it != modulesMap.end(); ++it)
×
1549
        {
1550
                // List of objects is not empty, let's add name of module or section!
1551
                if (!objectMgr->listAllModuleObjects(it.key(), ui->searchInEnglishCheckBox->isChecked()).isEmpty())
×
1552
                        objects->addItem(q_(it.value()), QVariant(it.key()));
×
1553
                else if (it.key()==selectedObjectId) // empty list is selected...
×
1554
                        selectedObjectId = defaultObjectId; // ...switch to default list
×
1555
        }
1556
        index = objects->findData(selectedObjectId, Qt::UserRole, Qt::MatchCaseSensitive);
×
1557
        objects->setCurrentIndex(index);
×
1558
        objects->model()->sort(0, Qt::AscendingOrder);
×
1559
        objects->blockSignals(false);
×
1560
        updateListView(objects->currentIndex());
×
1561
}
×
1562

1563
void SearchDialog::showContextMenu(const QPoint &pt)
×
1564
{
1565
        QMenu *menu = ui->lineEditSearchSkyObject->createStandardContextMenu();
×
1566
        menu->addSeparator();
×
1567
        QString clipText;
×
1568
        QClipboard *clipboard = QApplication::clipboard();
×
1569
        if (clipboard)
×
1570
                clipText = clipboard->text();
×
1571
        if (!clipText.isEmpty())
×
1572
        {
1573
                if (clipText.length()>12)
×
1574
                        clipText = clipText.right(9) + "...";
×
1575
                clipText = "\t(" + clipText + ")";
×
1576
        }
1577

1578
        menu->addAction(q_("Paste and Search") + clipText, this, SLOT(pasteAndGo()));
×
1579
        menu->exec(ui->lineEditSearchSkyObject->mapToGlobal(pt));
×
1580
        delete menu;
×
1581
}
×
1582

1583
void SearchDialog::pasteAndGo()
×
1584
{
1585
        // 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
1586
        ui->lineEditSearchSkyObject->setText(""); // clear current text
×
1587
        ui->lineEditSearchSkyObject->paste(); // paste text from clipboard
×
1588
        gotoObject(); // go to first found object
×
1589
}
×
1590

1591
void SearchDialog::setVisible(bool v)
×
1592
{
1593
        StelDialog::setVisible(v);
×
1594

1595
        // if from a previous search action, the first tab is shown but input line is not in focus,
1596
        // force focus on input line.
1597
        if (v && (ui->tabWidget->currentIndex()==0))
×
1598
        {
1599
                ui->lineEditSearchSkyObject->setFocus(Qt::PopupFocusReason);
×
1600
        }
1601
}
×
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