1 /*
2  * Stellarium
3  * Copyright (C) 2020 Jocelyn GIROD
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 #include <StelTranslator.hpp>
21 #include <QDir>
22 #include <QUuid>
23 
24 #include "StelApp.hpp"
25 #include "StelObjectMgr.hpp"
26 #include "StelModuleMgr.hpp"
27 #include "StelLocationMgr.hpp"
28 #include "StelFileMgr.hpp"
29 #include "StelMovementMgr.hpp"
30 #include "CustomObjectMgr.hpp"
31 #include "HighlightMgr.hpp"
32 #include "StarMgr.hpp"
33 #include "StelJsonParser.hpp"
34 #include "StelUtils.hpp"
35 #include "ObsListDialog.hpp"
36 #include "LabelMgr.hpp"
37 
38 #include "ui_obsListDialog.h"
39 
40 using namespace std;
41 
42 
ObsListDialog(QObject * parent)43 ObsListDialog::ObsListDialog ( QObject* parent ) : StelDialog ( "Observing list", parent )
44 {
45 	ui = new Ui_obsListDialogForm();
46 	core = StelApp::getInstance().getCore();
47 	objectMgr = GETSTELMODULE ( StelObjectMgr );
48 	labelMgr = GETSTELMODULE ( LabelMgr );
49 	obsListListModel = new QStandardItemModel ( 0,ColumnCount );
50 	observingListJsonPath = StelFileMgr::findFile ( "data", static_cast<StelFileMgr::Flags>( StelFileMgr::Directory|StelFileMgr::Writable ) ) + "/" + QString ( JSON_FILE_NAME );
51 	createEditDialog_instance = Q_NULLPTR;
52 	defaultListUuid_ = "";
53 }
54 
~ObsListDialog()55 ObsListDialog::~ObsListDialog()
56 {
57 	delete ui;
58 	delete obsListListModel;
59 }
60 
61 /*
62  * Initialize the dialog widgets and connect the signals/slots.
63 */
createDialogContent()64 void ObsListDialog::createDialogContent()
65 {
66 	ui->setupUi ( dialog );
67 
68 	//Signals and slots
69 	connect ( &StelApp::getInstance(), SIGNAL ( languageChanged() ), this, SLOT ( retranslate() ) );
70 	connect ( ui->closeStelWindow, SIGNAL ( clicked() ), this, SLOT ( close() ) );
71 
72 	connect ( ui->obsListNewListButton, SIGNAL ( clicked() ), this, SLOT ( obsListNewListButtonPressed() ) );
73 	connect ( ui->obsListEditListButton, SIGNAL ( clicked() ), this, SLOT ( obsListEditButtonPressed() ) );
74 	connect ( ui->obsListClearHighlightButton, SIGNAL ( clicked() ), this, SLOT ( obsListClearHighLightButtonPressed() ) );
75 	connect ( ui->obsListHighlightAllButton, SIGNAL ( clicked() ), this, SLOT ( obsListHighLightAllButtonPressed() ) );
76 	connect ( ui->obsListExitButton, SIGNAL ( clicked() ), this, SLOT ( obsListExitButtonPressed() ) );
77 	connect ( ui->obsListDeleteButton, SIGNAL ( clicked() ), this, SLOT ( obsListDeleteButtonPressed() ) );
78 	connect ( ui->obsListTreeView, SIGNAL ( doubleClicked ( QModelIndex ) ), this, SLOT ( selectAndGoToObject ( QModelIndex ) ) );
79 
80 	//BookmarksListCombo
81 	connect ( ui->obsListComboBox, SIGNAL ( activated ( int ) ), this, SLOT ( loadSelectedObservingList ( int ) ) );
82 
83 	//Initializing the list of observing list
84 	obsListListModel->setColumnCount ( ColumnCount );
85 	setObservingListHeaderNames();
86 
87 	ui->obsListTreeView->setModel ( obsListListModel );
88 	ui->obsListTreeView->header()->setSectionsMovable ( false );
89 	ui->obsListTreeView->header()->setSectionResizeMode ( ColumnName, QHeaderView::ResizeToContents );
90 	ui->obsListTreeView->header()->setSectionResizeMode ( ColumnType, QHeaderView::ResizeToContents );
91 	ui->obsListTreeView->header()->setSectionResizeMode ( ColumnRa, QHeaderView::ResizeToContents );
92 	ui->obsListTreeView->header()->setSectionResizeMode ( ColumnDec, QHeaderView::ResizeToContents );
93 	ui->obsListTreeView->header()->setSectionResizeMode ( ColumnConstellation, QHeaderView::ResizeToContents );
94 	ui->obsListTreeView->header()->setSectionResizeMode ( ColumnMagnitude, QHeaderView::ResizeToContents );
95 	ui->obsListTreeView->header()->setStretchLastSection ( true );
96 	ui->obsListTreeView->hideColumn ( ColumnUUID );
97 	ui->obsListTreeView->hideColumn ( ColumnNameI18n );
98 	ui->obsListTreeView->hideColumn ( ColumnJD );
99 	ui->obsListTreeView->hideColumn ( ColumnLocation );
100 	//Enable the sort for columns
101 	ui->obsListTreeView->setSortingEnabled ( true );
102 
103 	//First item of the combobox is an empty headerStrings
104 	ui->obsListComboBox->addItem ( "" );
105 	//By default buttons are disable
106 	ui->obsListEditListButton->setEnabled ( false );
107 	ui->obsListHighlightAllButton->setEnabled ( false );
108 	ui->obsListClearHighlightButton->setEnabled ( false );
109 	ui->obsListDeleteButton->setEnabled(false);
110 
111 	QFile jsonFile ( observingListJsonPath );
112 	if ( jsonFile.exists() )
113 	{
114 		loadListsName();
115 		loadDefaultList();
116 	}
117 }
118 
119 /*
120  * Retranslate dialog
121 */
retranslate()122 void ObsListDialog::retranslate()
123 {
124 	if ( dialog )
125 	{
126 		ui->retranslateUi ( dialog );
127 		setObservingListHeaderNames();
128 	}
129 }
130 
131 /*
132  * Style changed
133 */
styleChanged()134 void ObsListDialog::styleChanged()
135 {
136 	// Nothing for now
137 }
138 
139 /*
140  * Set the header for the observing list table
141  * (obsListTreeVView)
142 */
setObservingListHeaderNames()143 void ObsListDialog::setObservingListHeaderNames()
144 {
145 	const QStringList headerStrings = {
146 		"UUID", // Hided column
147 		q_( "Object name" ),
148 		q_( "Localized Object Name" ), // Hided column
149 		q_( "Type" ),
150 		q_( "Right ascension" ),
151 		q_( "Declination" ),
152 		q_( "Magnitude" ),
153 		q_( "Constellation" ),
154 		q_( "Date" ), // Hided column
155 		q_( "Location" ) // Hided column
156 	};
157 
158 	obsListListModel->setHorizontalHeaderLabels ( headerStrings );;
159 }
160 
161 /*
162  * Add row in the obsListListModel
163 */
addModelRow(int number,QString uuid,QString name,QString nameI18n,QString type,QString ra,QString dec,QString magnitude,QString constellation)164 void ObsListDialog::addModelRow ( int number, QString uuid, QString name, QString nameI18n, QString type, QString ra, QString dec, QString magnitude, QString constellation )
165 {
166 	QStandardItem* item = Q_NULLPTR;
167 
168 	item = new QStandardItem ( uuid );
169 	item->setEditable ( false );
170 	obsListListModel->setItem ( number, ColumnUUID, item );
171 
172 	item = new QStandardItem ( name );
173 	item->setEditable ( false );
174 	obsListListModel->setItem ( number, ColumnName, item );
175 
176 	item = new QStandardItem ( nameI18n );
177 	item->setEditable ( false );
178 	obsListListModel->setItem ( number, ColumnNameI18n, item );
179 
180 	item = new QStandardItem ( type );
181 	item->setEditable ( false );
182 	obsListListModel->setItem ( number, ColumnType, item );
183 
184 	item = new QStandardItem ( ra );
185 	item->setEditable ( false );
186 	obsListListModel->setItem ( number, ColumnRa, item );
187 
188 	item = new QStandardItem ( dec );
189 	item->setEditable ( false );
190 	obsListListModel->setItem ( number, ColumnDec, item );
191 
192 	item = new QStandardItem ( magnitude );
193 	item->setEditable ( false );
194 	obsListListModel->setItem ( number, ColumnMagnitude, item );
195 
196 	item = new QStandardItem ( constellation );
197 	item->setEditable ( false );
198 	obsListListModel->setItem ( number, ColumnConstellation, item );
199 
200 	for ( int i = 0; i < ColumnCount; ++i ) {
201 		ui->obsListTreeView->resizeColumnToContents ( i );
202 	}
203 }
204 
205 /*
206  * Slot for button obsListHighLightAllButton
207 */
obsListHighLightAllButtonPressed()208 void ObsListDialog::obsListHighLightAllButtonPressed()
209 {
210 	QList<Vec3d> highlights;
211 	highlights.clear();
212 	obsListClearHighLightButtonPressed(); // Enable fool protection
213 	int fontSize = StelApp::getInstance().getScreenFontSize();
214 	HighlightMgr* hlMgr = GETSTELMODULE ( HighlightMgr );
215 	QString color = hlMgr->getColor().toHtmlColor();
216 	float distance = hlMgr->getMarkersSize();
217 
218 	for ( auto item : observingListItemCollection )
219 	{
220 		QString name	= item.name;
221 		QString raStr	= item.ra.trimmed();
222 		QString decStr	= item.dec.trimmed();
223 
224 		Vec3d pos;
225 		bool status = false;
226 		if ( !raStr.isEmpty() && !decStr.isEmpty() )
227 		{
228 			StelUtils::spheToRect ( StelUtils::getDecAngle ( raStr ), StelUtils::getDecAngle ( decStr ), pos );
229 			status = true;
230 		}
231 		else
232 		{
233 			status = objectMgr->findAndSelect ( name );
234 			const QList<StelObjectP>& selected = objectMgr->getSelectedObject();
235 			if ( !selected.isEmpty() )
236 				pos = selected[0]->getJ2000EquatorialPos ( core );
237 		}
238 
239 		if ( status )
240 			highlights.append ( pos );
241 
242 		objectMgr->unSelect();
243 		// Add labels for named highlights (name in top right corner)
244 		highlightLabelIDs.append ( labelMgr->labelObject ( name, name, true, fontSize, color, "NE", distance ) );
245 	}
246 
247 	hlMgr->fillHighlightList ( highlights );
248 }
249 
250 /*
251  * Slot for button obsListClearHighLightButton
252 */
obsListClearHighLightButtonPressed()253 void ObsListDialog::obsListClearHighLightButtonPressed()
254 {
255 	objectMgr->unSelect();
256 	GETSTELMODULE ( HighlightMgr )->cleanHighlightList();
257 	// Clear labels
258 	for ( auto l : highlightLabelIDs )
259 		labelMgr->deleteLabel ( l );
260 
261 	highlightLabelIDs.clear();
262 }
263 
264 /*
265  * Slot for button obsListNewListButton
266 */
obsListNewListButtonPressed()267 void ObsListDialog::obsListNewListButtonPressed()
268 {
269 	string listUuid = string();
270 	invokeObsListCreateEditDialog ( listUuid );
271 }
272 
273 /*
274  * Slot for button obsListEditButton
275 */
obsListEditButtonPressed()276 void ObsListDialog::obsListEditButtonPressed()
277 {
278 	if ( !selectedObservingListUuid.empty() )
279 		invokeObsListCreateEditDialog ( selectedObservingListUuid );
280 	else
281 		qWarning() << "The selected observing list uuid is empty";
282 }
283 
284 /**
285  * Open the observing list create/edit dialog
286 */
invokeObsListCreateEditDialog(string listUuid)287 void ObsListDialog::invokeObsListCreateEditDialog ( string listUuid )
288 {
289 	createEditDialog_instance = ObsListCreateEditDialog::Instance ( listUuid );
290 	connect ( createEditDialog_instance, SIGNAL ( exitButtonClicked() ), this, SLOT ( obsListCreateEditDialogClosed() ) );
291 	createEditDialog_instance->setVisible ( true );
292 }
293 
294 /*
295  * Load the lists names for populate the combo box and get the default list uuid
296 */
loadListsName()297 void ObsListDialog::loadListsName()
298 {
299 	QVariantMap map;
300 	QFile jsonFile ( observingListJsonPath );
301 	if ( !jsonFile.open ( QIODevice::ReadOnly ) )
302 		qWarning() << "[ObservingList] cannot open" << QDir::toNativeSeparators ( JSON_FILE_NAME );
303 	else
304 	{
305 		try {
306 			map = StelJsonParser::parse ( jsonFile.readAll() ).toMap();
307 			jsonFile.close();
308 
309 			// init combo box
310 			ui->obsListComboBox->clear();
311 			ui->obsListComboBox->addItem ( "" );
312 
313 			// Get the default list uuid
314 			QString defaultListUuid = map.value ( KEY_DEFAULT_LIST_UUID ).toString();
315 
316 			QVariantMap observingListsMap = map.value ( QString ( KEY_OBSERVING_LISTS ) ).toMap();
317 
318 			QMap<QString, QVariant>::iterator i;
319 			for ( i = observingListsMap.begin(); i != observingListsMap.end(); ++i )
320 			{
321 				QString listUuid = i.key();
322 
323 				if ( i.value().canConvert<QVariantMap>() )
324 				{
325 					QVariant var = i.value();
326 					QVariantMap data = var.value<QVariantMap>();
327 					QString listName = data.value ( KEY_NAME ).value<QString>();
328 					ui->obsListComboBox->addItem ( listName, listUuid );
329 					if ( defaultListUuid == listUuid )
330 						defaultListUuid_ = defaultListUuid;
331 				}
332 			}
333 		}
334 		catch ( std::runtime_error &e )
335 		{
336 			qWarning() << "[ObservingList] File format is wrong! Error: " << e.what();
337 			return;
338 		}
339 	}
340 }
341 
342 /*
343  * Load the default list
344 */
loadDefaultList()345 void ObsListDialog::loadDefaultList()
346 {
347 	if ( defaultListUuid_ != "" )
348 	{
349 		int index = ui->obsListComboBox->findData ( defaultListUuid_ );
350 		if ( index != -1 )
351 		{
352 			ui->obsListComboBox->setCurrentIndex ( index );
353 			ui->obsListEditListButton->setEnabled ( true );
354 			selectedObservingListUuid = defaultListUuid_.toStdString();
355 			loadObservingList ( defaultListUuid_ );
356 		}
357 	}
358 }
359 
360 /*
361  * Load selected observing list
362 */
loadObservingList(QString listUuid)363 void ObsListDialog::loadObservingList ( QString listUuid )
364 {
365 	QVariantMap map;
366 	QVariantList listOfObjects;
367 	QFile jsonFile ( observingListJsonPath );
368 	if ( !jsonFile.open ( QIODevice::ReadOnly ) )
369 		qWarning() << "[ObservingList] cannot open" << QDir::toNativeSeparators ( JSON_FILE_NAME );
370 	else {
371 		try {
372 			listOfObjects = loadListFromJson(jsonFile, listUuid);
373 
374 			if ( listOfObjects.size() > 0 )
375 			{
376 				ui->obsListHighlightAllButton->setEnabled ( true );
377 				ui->obsListClearHighlightButton->setEnabled ( true );
378 				ui->obsListDeleteButton->setEnabled(true);
379 
380 				for ( QVariant object: listOfObjects )
381 				{
382 					QVariantMap objectMap;
383 					if ( object.canConvert<QVariantMap>() )
384 					{
385 						objectMap = object.value<QVariantMap>();
386 						QString objectName = objectMap.value ( QString ( KEY_DESIGNATION ) ).value<QString>();
387 
388 						if ( objectMgr->findAndSelect ( objectName ) )
389 						{
390 							const QList<StelObjectP>& selectedObject = objectMgr->getSelectedObject();
391 							if ( !selectedObject.isEmpty() )
392 							{
393 								int lastRow = obsListListModel->rowCount();
394 								QString objectUuid = QUuid::createUuid().toString();
395 								QString objectNameI18n = selectedObject[0]->getNameI18n();
396 								QString objectRaStr = "", objectDecStr = "";
397 								bool visibleFlag = false;
398 								double fov = -1.0;
399 
400 								QString objectType = selectedObject[0]->getType();
401 
402 								double ra, dec;
403 								StelUtils::rectToSphe ( &ra, &dec, selectedObject[0]->getJ2000EquatorialPos ( core ) );
404 								objectRaStr = StelUtils::radToHmsStr ( ra, false ).trimmed();
405 								objectDecStr = StelUtils::radToDmsStr ( dec, false ).trimmed();
406 								if ( objectName.contains ( "marker", Qt::CaseInsensitive ) )
407 									visibleFlag = true;
408 
409 								float objectMagnitude = selectedObject[0]->getVMagnitude ( core );
410 								QString objectMagnitudeStr = QString::number ( objectMagnitude );
411 
412 								QVariantMap objectMap = selectedObject[0]->getInfoMap ( core );
413 								QVariant objectConstellationVariant = objectMap["iauConstellation"];
414 								QString objectConstellation ( "unknown" );
415 								if ( objectConstellationVariant.canConvert<QString>() )
416 									objectConstellation = objectConstellationVariant.value<QString>();
417 
418 								QString JDs = "";
419 								double JD = core->getJD();
420 
421 								JDs = StelUtils::julianDayToISO8601String ( JD + core->getUTCOffset ( JD ) /24. ).replace ( "T", " " );
422 
423 								QString Location = "";
424 								StelLocation loc = core->getCurrentLocation();
425 								if ( loc.name.isEmpty() )
426 									Location = QString ( "%1, %2" ).arg ( loc.latitude ).arg ( loc.longitude );
427 								else
428 									Location = QString ( "%1, %2" ).arg ( loc.name ).arg ( loc.region );
429 
430 								addModelRow ( lastRow,objectUuid,objectName, objectNameI18n, objectType, objectRaStr, objectDecStr, objectMagnitudeStr, objectConstellation );
431 
432 								observingListItem item;
433 								item.name = objectName;
434 								item.nameI18n = objectNameI18n;
435 								if ( !objectType.isEmpty() )
436 									item.type = objectType;
437 
438 								if ( !objectRaStr.isEmpty() )
439 									item.ra = objectRaStr;
440 
441 								if ( !objectDecStr.isEmpty() )
442 									item.dec = objectDecStr;
443 
444 								if ( !objectMagnitudeStr.isEmpty() )
445 									item.magnitude = objectMagnitudeStr;
446 
447 								if ( !objectConstellation.isEmpty() )
448 									item.constellation = objectConstellation;
449 
450 								if ( !JDs.isEmpty() )
451 									item.jd	= QString::number ( JD, 'f', 6 );
452 
453 								if ( !Location.isEmpty() )
454 									item.location = Location;
455 
456 								if ( !visibleFlag )
457 									item.isVisibleMarker = visibleFlag;
458 
459 								if ( fov > 0.0 )
460 									item.fov = fov;
461 
462 								observingListItemCollection.insert ( objectUuid,item );
463 							}
464 							else
465 								qWarning() << "[ObservingList] selected object is empty !";
466 						}
467 						else
468 							qWarning() << "[ObservingList] object: " << objectName << " not found !" ;
469 					}
470 					else
471 					{
472 						qCritical() << "[ObservingList] conversion error";
473 						return;
474 					}
475 				}
476 			}
477 			else
478 			{
479 				ui->obsListHighlightAllButton->setEnabled ( false );
480 				ui->obsListClearHighlightButton->setEnabled ( false );
481 				ui->obsListDeleteButton->setEnabled(false);
482 			}
483 
484 			objectMgr->unSelect();
485 		}
486 		catch ( std::runtime_error &e )
487 		{
488 			qWarning() << "[ObservingList] File format is wrong! Error: " << e.what();
489 			return;
490 		}
491 	}
492 }
493 
494 /*
495  * Load the list from JSON file
496 */
loadListFromJson(QFile & jsonFile,QString listUuid)497 QVariantList ObsListDialog::loadListFromJson(QFile &jsonFile, QString listUuid)
498 {
499 	QVariantMap map;
500 	map = StelJsonParser::parse ( jsonFile.readAll() ).toMap();
501 	jsonFile.close();
502 
503 	observingListItemCollection.clear();
504 	QVariantMap observingListMap = map.value ( QString ( KEY_OBSERVING_LISTS ) ).toMap().value ( listUuid ).toMap();
505 	QVariantList listOfObjects;
506 
507 	QString listDescription = observingListMap.value ( QString ( KEY_DESCRIPTION ) ).value<QString>();
508 	ui->obsListDescriptionTextEdit->setPlainText ( listDescription );
509 
510 	// Displaying the creation date
511 	QString JDs = observingListMap.value ( QString ( KEY_JD ) ).value<QString>();
512 	double JD = JDs.toDouble();
513 	QString listCreationDate = JDs = StelUtils::julianDayToISO8601String ( JD + core->getUTCOffset ( JD ) /24. ).replace ( "T", " " );
514 	ui->obsListCreationDateLineEdit->setText ( listCreationDate );
515 
516 	if ( observingListMap.value ( QString ( KEY_OBJECTS ) ).canConvert<QVariantList>() )
517 	{
518 		QVariant data = observingListMap.value ( QString ( KEY_OBJECTS ) );
519 		listOfObjects = data.value<QVariantList>();
520 	}
521 	else
522 		qCritical() << "[ObservingList] conversion error";
523 
524 	// Clear model
525 	obsListListModel->removeRows ( 0,obsListListModel->rowCount() );
526 	return listOfObjects;
527 }
528 
529 
530 /*
531  * Select and go to object
532 */
selectAndGoToObject(QModelIndex index)533 void ObsListDialog::selectAndGoToObject ( QModelIndex index )
534 {
535 	QStandardItem * selectedItem = obsListListModel->itemFromIndex ( index );
536 	int rawNumber = selectedItem->row();
537 
538 	QStandardItem * uuidItem = obsListListModel->item ( rawNumber, ColumnUUID );
539 	QString itemUuid = uuidItem->text();
540 	observingListItem item = observingListItemCollection.value ( itemUuid );
541 
542 	if ( !item.jd.isEmpty() )
543 		core->setJD ( item.jd.toDouble() );
544 
545 	if ( !item.location.isEmpty() )
546 	{
547 		StelLocationMgr* locationMgr = &StelApp::getInstance().getLocationMgr();
548 		core->moveObserverTo ( locationMgr->locationForString ( item.location ) );
549 	}
550 
551 	StelMovementMgr* mvmgr = GETSTELMODULE ( StelMovementMgr );
552 	objectMgr->unSelect();
553 
554 	bool status = objectMgr->findAndSelect ( item.name );
555 	float amd = mvmgr->getAutoMoveDuration();
556 	if ( !item.ra.isEmpty() && !item.dec.isEmpty() && !status )
557 	{
558 		Vec3d pos;
559 		StelUtils::spheToRect ( StelUtils::getDecAngle ( item.ra.trimmed() ), StelUtils::getDecAngle ( item.dec.trimmed() ), pos );
560 		if ( item.name.contains ( "marker", Qt::CaseInsensitive ) )
561 		{
562 			// Add a custom object on the sky
563 			GETSTELMODULE ( CustomObjectMgr )->addCustomObject ( item.name, pos, item.isVisibleMarker );
564 			status = objectMgr->findAndSelect ( item.name );
565 		}
566 		else
567 		{
568 			// The unnamed stars
569 			StelObjectP sobj;
570 			const StelProjectorP prj = core->getProjection ( StelCore::FrameJ2000 );
571 			double fov = 5.0;
572 			if ( item.fov > 0.0 )
573 				fov = item.fov;
574 
575 			mvmgr->zoomTo ( fov, 0.0 );
576 			mvmgr->moveToJ2000 ( pos, mvmgr->mountFrameToJ2000 ( Vec3d ( 0., 0., 1. ) ), 0.0 );
577 
578 			QList<StelObjectP> candidates = GETSTELMODULE ( StarMgr )->searchAround ( pos, 0.5, core );
579 			if ( candidates.empty() )
580 			{ // The FOV is too big, let's reduce it
581 				mvmgr->zoomTo ( 0.5*fov, 0.0 );
582 				candidates = GETSTELMODULE ( StarMgr )->searchAround ( pos, 0.5, core );
583 			}
584 
585 			double best_object_value = M_PI;
586 			for ( const auto& obj : candidates )
587 			{
588 				double distance=pos.angle(obj->getJ2000EquatorialPos(core));
589 				if ( distance < best_object_value )
590 				{
591 					best_object_value = distance;
592 					sobj = obj;
593 				}
594 			}
595 
596 			if ( sobj )
597 				status = objectMgr->setSelectedObject ( sobj );
598 		}
599 	}
600 
601 	if ( status )
602 	{
603 		const QList<StelObjectP> newSelected = objectMgr->getSelectedObject();
604 		if ( !newSelected.empty() )
605 		{
606 			mvmgr->moveToObject ( newSelected[0], amd );
607 			mvmgr->setFlagTracking ( true );
608 		}
609 	}
610 }
611 
612 /*
613  * Method called when a list name is selected in the combobox
614 */
loadSelectedObservingList(int selectedIndex)615 void ObsListDialog::loadSelectedObservingList ( int selectedIndex )
616 {
617 	if ( selectedIndex > 0 )
618 	{
619 		ui->obsListEditListButton->setEnabled ( true );
620 		ui->obsListDeleteButton->setEnabled(true);
621 		QString listUuid = ui->obsListComboBox->itemData ( selectedIndex ).toString();
622 		selectedObservingListUuid = listUuid.toStdString();
623 		loadObservingList ( listUuid );
624 	}
625 	else
626 	{
627 		selectedObservingListUuid = "";
628 		// Button obsListEditListButton, obsListHighlightAllButton and
629 		// obsListClearHighlightButtonmust be disable if no list is selected
630 		ui->obsListEditListButton->setEnabled ( false );
631 		ui->obsListHighlightAllButton->setEnabled ( false );
632 		ui->obsListClearHighlightButton->setEnabled ( false );
633 		ui->obsListDeleteButton->setEnabled(false);
634 		// Clear list description
635 		ui->obsListDescriptionTextEdit->setPlainText ( "" );
636 		// Clear model
637 		obsListListModel->removeRows ( 0,obsListListModel->rowCount() );
638 		qWarning() << "[ObservingList] No list selected !";
639 	}
640 }
641 
642 /*
643  * Delete the selected list
644 */
obsListDeleteButtonPressed()645 void ObsListDialog::obsListDeleteButtonPressed()
646 {
647 	qDebug() << QString::fromStdString(selectedObservingListUuid);
648 	QVariantMap map;
649 	QFile jsonFile ( observingListJsonPath );
650 	if ( !jsonFile.open ( QIODevice::ReadWrite ) )
651 		qWarning() << "[ObservingList] cannot open" << QDir::toNativeSeparators ( JSON_FILE_NAME );
652 	else
653 	{
654 		try
655 		{
656 			QVariantMap newMap;
657 			QVariantMap newObsListMap;
658 			map = StelJsonParser::parse ( jsonFile.readAll() ).toMap();
659 
660 			newMap.insert(QString(KEY_DEFAULT_LIST_UUID), map.value(QString(KEY_DEFAULT_LIST_UUID)));
661 			QVariantMap obsListMap = map.value(QString(KEY_OBSERVING_LISTS)).toMap();
662 
663 			QMap<QString, QVariant>::iterator i;
664 			for(i = obsListMap.begin(); i != obsListMap.end(); ++i)
665 			{
666 				if(i.key().compare(QString::fromStdString(selectedObservingListUuid))!=0)
667 					newObsListMap.insert(i.key(),i.value());
668 			}
669 
670 			newMap.insert(QString(KEY_OBSERVING_LISTS),newObsListMap);
671 			newMap.insert(QString(KEY_SHORT_NAME), map.value(QString(KEY_SHORT_NAME)));
672 			newMap.insert(QString(KEY_VERSION), map.value(QString(KEY_VERSION)));
673 			objectMgr->unSelect();
674 			observingListItemCollection.clear();
675 			// Clear model
676 			obsListListModel->removeRows ( 0,obsListListModel->rowCount() );
677 			ui->obsListCreationDateLineEdit->setText("");
678 			int currentIndex = ui->obsListComboBox->currentIndex();
679 			ui->obsListComboBox->removeItem(currentIndex);
680 
681 			int index = ui->obsListComboBox->findData("");
682 			ui->obsListComboBox->setCurrentIndex(index);
683 			ui->obsListDescriptionTextEdit->setPlainText("");
684 
685 			jsonFile.resize ( 0 );
686 			StelJsonParser::write ( newMap, &jsonFile );
687 			jsonFile.flush();
688 			jsonFile.close();
689 
690 		}
691 		catch ( std::runtime_error &e )
692 		{
693 			qWarning() << "[ObservingList] File format is wrong! Error: " << e.what();
694 			return;
695 		}
696 	}
697 }
698 
699 /*
700  * Slot for button obsListExitButton
701 */
obsListExitButtonPressed()702 void ObsListDialog::obsListExitButtonPressed()
703 {
704 	this->close();
705 }
706 
707 /*
708  * Slot to manage the close of obsListCreateEditDialog
709 */
obsListCreateEditDialogClosed()710 void ObsListDialog::obsListCreateEditDialogClosed()
711 {
712 	// We must reload the list of list name
713 	loadListsName();
714 	int index = ui->obsListComboBox->findData ( QString::fromStdString ( selectedObservingListUuid ) ) ;
715 	if ( index != -1 )
716 	{
717 		ui->obsListComboBox->setCurrentIndex ( index );
718 		loadSelectedObservingList ( index );
719 	}
720 
721 	ObsListCreateEditDialog::kill();
722 	createEditDialog_instance = Q_NULLPTR;
723 }
724