Commit e498f19a authored by Artem Fedoskin's avatar Artem Fedoskin
Browse files

Added "Set Geolocation" page. User can set location either manualy or by

getting latitude and longitude from device sensors (GPS, Wi-Fi etc.).
Changed the structure of QML part of the project.
parent a520f0ec
......@@ -32,7 +32,7 @@ set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH})
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" ${CMAKE_MODULE_PATH})
if(BUILD_KSTARS_LITE)
find_package(Qt5 5.7 REQUIRED COMPONENTS Gui Qml Quick QuickControls2 Xml Svg Sql Network Sensors)
find_package(Qt5 5.7 REQUIRED COMPONENTS Gui Qml Quick QuickControls2 Xml Svg Sql Network Sensors Positioning)
else()
find_package(Qt5 5.4 REQUIRED COMPONENTS Gui Qml Quick Xml Sql Svg Network PrintSupport)
endif()
......
......@@ -38,6 +38,7 @@
</activity>
</application>
<supports-screens android:anyDensity="true" android:normalScreens="true" android:smallScreens="true" android:largeScreens="true"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
......
......@@ -585,6 +585,7 @@ if(BUILD_KSTARS_LITE)
#Dialogs
kstarslite/dialogs/detaildialoglite.cpp
kstarslite/dialogs/finddialoglite.cpp
kstarslite/dialogs/locationdialoglite.cpp
kstarslite/dialogs/skyobjectlistmodel.cpp
#RootNode
kstarslite/skyitems/rootnode.cpp
......@@ -668,23 +669,29 @@ if(BUILD_KSTARS_LITE)
kstarslite/qml/modules/Splash.qml
kstarslite/qml/modules/helpers/TimeSpinBox.qml
kstarslite/qml/modules/TimePage.qml
kstarslite/qml/modules/ObjectDetails.qml
kstarslite/qml/modules/KSTab.qml
#Popups
kstarslite/qml/modules/popups/ProjectionsPopup.qml
kstarslite/qml/modules/popups/FOVPopup.qml
kstarslite/qml/modules/popups/ColorSchemePopup.qml
kstarslite/qml/modules/popups/AddLinkPopup.qml
kstarslite/qml/modules/popups/LinkMenu.qml
#Menus
kstarslite/qml/modules/menus/ContextMenu.qml
#Helpers
kstarslite/qml/modules/helpers/PassiveNotification.qml
kstarslite/qml/modules/helpers/KSMenuItem.qml
kstarslite/qml/modules/helpers/DetailsItem.qml
kstarslite/qml/modules/helpers/TelescopeControl.qml
#Dialogs
kstarslite/qml/dialogs/FindDialog.qml
kstarslite/qml/dialogs/LocationDialog.qml
kstarslite/qml/dialogs/DetailsDialog.qml
kstarslite/qml/dialogs/helpers/DetailsItem.qml
kstarslite/qml/dialogs/helpers/DetailsAddLink.qml
kstarslite/qml/dialogs/helpers/LocationEdit.qml
kstarslite/qml/dialogs/helpers/LocationLoading.qml
kstarslite/qml/dialogs/menus/DetailsLinkMenu.qml
kstarslite/qml/dialogs/menus/LocationsGeoMenu.qml
#INDI
kstarslite/qml/indi/INDIControlPanel.qml
kstarslite/qml/indi/DevicePanel.qml
......@@ -828,6 +835,7 @@ if(BUILD_KSTARS_LITE)
Qt5::Quick
Qt5::Sensors
Qt5::QuickControls2
Qt5::Positioning
${ZLIB_LIBRARIES}
)
if(INDI_FOUND)
......
......@@ -488,6 +488,16 @@ bool LocationDialog::checkLongLat() {
return true;
}
dms LocationDialog::createDms ( bool deg, bool *ok )
{
dms dmsAngle(0.0); // FIXME: Should we change this to NaN?
bool check;
check = dmsAngle.setFromString( text(), deg );
if (ok) *ok = check; //ok might be a null pointer!
return dmsAngle;
}
void LocationDialog::clearFields()
{
ld->CityFilter->clear();
......
......@@ -92,6 +92,7 @@ public:
friend class SkyMap;
// FIXME: uses geoList and changes it.
friend class LocationDialog;
friend class LocationDialogLite;
static KStarsData* Create( );
......
......@@ -33,9 +33,10 @@
#include "kspaths.h"
//Dialog
//Dialogs
#include "kstarslite/dialogs/finddialoglite.h"
#include "kstarslite/dialogs/detaildialoglite.h"
#include "kstarslite/dialogs/locationdialoglite.h"
#include "Options.h"
#include "ksutils.h"
......@@ -76,8 +77,11 @@ KStarsLite::KStarsLite( bool doSplash, bool startClock, const QString &startDate
//Dialogs
m_findDialogLite = new FindDialogLite;
m_detailDialogLite = new DetailDialogLite;
m_locationDialogLite = new LocationDialogLite;
m_Engine.rootContext()->setContextProperty("FindDialogLite", m_findDialogLite);
m_Engine.rootContext()->setContextProperty("DetailDialogLite", m_detailDialogLite);
m_Engine.rootContext()->setContextProperty("LocationDialogLite", m_locationDialogLite);
//Set Geographic Location from Options
m_KStarsData->setLocationFromOptions();
......
......@@ -34,6 +34,7 @@ class ImageProvider;
class FindDialogLite;
class DetailDialogLite;
class LocationDialogLite;
#ifdef INDI_FOUND
class ClientManagerLite;
......@@ -203,7 +204,8 @@ private:
//Dialogs
FindDialogLite *m_findDialogLite;
DetailDialogLite *m_detailDialogLite;
LocationDialogLite *m_locationDialogLite;
#ifdef INDI_FOUND
ClientManagerLite *m_clientManager;
#endif
......
......@@ -584,6 +584,8 @@ void DetailDialogLite::updateLocalDatabase(int type, const QString &search_line,
void DetailDialogLite::addLink(QString url, QString desc, bool isImageLink) {
SkyObject *selectedObject = SkyMapLite::Instance()->getClickedObjectLite()->getObject();
if(url.isEmpty() || desc.isEmpty()) return; //Do nothing if empty url or desc were provided
QString entry;
QFile file;
......@@ -691,6 +693,8 @@ void DetailDialogLite::editLink(int itemIndex, bool isImage, QString desc, QStri
{
SkyObject *selectedObject = SkyMapLite::Instance()->getClickedObjectLite()->getObject();
if(url.isEmpty() || desc.isEmpty()) return; //Do nothing if empty url or desc were provided
QString search_line, replace_line, currentItemTitle, currentItemURL;
//Check if it is a valid index
......
......@@ -64,46 +64,6 @@ FindDialogLite::FindDialogLite( ) :
FindDialogLite::~FindDialogLite() { }
/*void FindDialogLite::initSelection() {
if ( m_sortModel->rowCount() <= 0 )
{
return;
}
//if ( ui->SearchBox->text().isEmpty() ) {
//Pre-select the first item
QModelIndex selectItem = m_sortModel->index( 0, m_sortModel->filterKeyColumn(), QModelIndex() );
switch ( 0) {//ui->FilterType->currentIndex() ) {
case 0: //All objects, choose Andromeda galaxy
{
QModelIndex qmi = fModel->index( fModel->stringList().indexOf( i18n("Andromeda Galaxy") ) );
selectItem = m_sortModel->mapFromSource( qmi );
break;
}
case 1: //Stars, choose Aldebaran
{
QModelIndex qmi = fModel->index( fModel->stringList().indexOf( i18n("Aldebaran") ) );
selectItem = m_sortModel->mapFromSource( qmi );
break;
}
case 2: //Solar system or Asteroids, choose Aaltje
case 9:
{
QModelIndex qmi = fModel->index( fModel->stringList().indexOf( i18n("Aaltje") ) );
selectItem = m_sortModel->mapFromSource( qmi );
break;
}
case 8: //Comets, choose 'Aarseth-Brewington (1989 W1)'
{
QModelIndex qmi = fModel->index( fModel->stringList().indexOf( i18n("Aarseth-Brewington (1989 W1)") ) );
selectItem = m_sortModel->mapFromSource( qmi );
break;
}
}
//listFiltered = true;
}*/
void FindDialogLite::filterByType(uint typeIndex) {
KStarsData *data = KStarsData::Instance();
......@@ -172,20 +132,6 @@ void FindDialogLite::filterByType(uint typeIndex) {
void FindDialogLite::filterList(QString searchQuery) {
QString SearchText = processSearchText(searchQuery);
m_sortModel->setFilterFixedString( SearchText );
//filterByType();
//initSelection();
//Select the first item in the list that begins with the filter string
/*if ( !SearchText.isEmpty() ) {
QStringList mItems = fModel->stringList().filter( QRegExp( '^'+SearchText, Qt::CaseInsensitive ) );
mItems.sort();
if ( mItems.size() ) {
QModelIndex qmi = fModel->index( fModel->stringList().indexOf( mItems[0] ) );
QModelIndex selectItem = m_sortModel->mapFromSource( qmi );
}
}*/
listFiltered = true;
}
......@@ -195,18 +141,6 @@ void FindDialogLite::selectObject(int index) {
SkyMapLite::Instance()->slotSelectObject(skyObj);
}
void FindDialogLite::enqueueSearch() {
/*listFiltered = false;
if ( timer ) {
timer->stop();
} else {
timer = new QTimer( this );
timer->setSingleShot( true );
connect( timer, SIGNAL( timeout() ), this, SLOT( filterList() ) );
}
timer->start( 500 );*/
}
// Process the search box text to replace equivalent names like "m93" with "m 93"
QString FindDialogLite::processSearchText(QString text) {
QRegExp re;
......@@ -231,56 +165,3 @@ QString FindDialogLite::processSearchText(QString text) {
return searchtext;
}
void FindDialogLite::slotOk() {
/*//If no valid object selected, show a sorry-box. Otherwise, emit accept()
SkyObject *selObj;
if(!listFiltered) {
filterList();
}
selObj = selectedObject();
if ( selObj == 0 ) {
QString message = i18n( "No object named %1 found.", ui->SearchBox->text() );
//KMessageBox::sorry( 0, message, i18n( "Bad object name" ) );
} else {
accept();
}*/
}
/*void FindDialogLite::keyPressEvent( QKeyEvent *e ) {
switch( e->key() ) {
case Qt::Key_Escape :
reject();
break;
case Qt::Key_Up :
{
int currentRow = ui->SearchList->currentIndex().row();
if ( currentRow > 0 ) {
QModelIndex selectItem = m_sortModel->index( currentRow-1, m_sortModel->filterKeyColumn(), QModelIndex() );
ui->SearchList->selectionModel()->setCurrentIndex( selectItem, QItemSelectionModel::SelectCurrent );
}
break;
}
case Qt::Key_Down :
{
int currentRow = ui->SearchList->currentIndex().row();
if ( currentRow < m_sortModel->rowCount()-1 ) {
QModelIndex selectItem = m_sortModel->index( currentRow+1, m_sortModel->filterKeyColumn(), QModelIndex() );
ui->SearchList->selectionModel()->setCurrentIndex( selectItem, QItemSelectionModel::SelectCurrent );
}
break;
}
}
}*/
void FindDialogLite::slotDetails()
{
/*if ( selectedObject() ) {
QPointer<DetailDialog> dd = new DetailDialog( selectedObject(), KStarsData::Instance()->ut(), KStarsData::Instance()->geo(), KStars::Instance());
dd->exec();
delete dd;
}*/
}
......@@ -60,18 +60,6 @@ public slots:
*/
Q_INVOKABLE void filterList(QString searchQuery);
//FIXME: Still valid for QDialog? i.e., does QDialog have a slotOk() ?
/**
*Overloading the Standard QDialogBase slotOk() to show a "sorry" message
*box if no object is selected when the user presses Ok. The window is
*not closed in this case.
*/
void slotOk();
private slots:
void enqueueSearch();
void slotDetails();
private:
/** @short Do some post processing on the search text to interpret what the user meant
......
/***************************************************************************
locationialoglite.cpp - K Desktop Planetarium
-------------------
begin : Sun Aug 21 2016
copyright : (C) 2016 by Artem Fedoskin
email : afedoskin3@gmail.com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "locationdialoglite.h"
#include "kstarsdata.h"
#include "kstarslite.h"
#include <QQmlContext>
#include "kspaths.h"
LocationDialogLite::LocationDialogLite()
:SelectedCity(nullptr), currentGeo(nullptr){
// KStarsData* data = KStarsData::Instance();
// SelectedCity = NULL;
// setWindowTitle( i18n( "Set Geographic Location" ) );
// QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel);
// mainLayout->addWidget(buttonBox);
// connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotOk()));
// connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
// for ( int i=0; i<25; ++i )
// ld->TZBox->addItem( QLocale().toString( (double)(i-12) ) );
// //Populate DSTRuleBox
// foreach( const QString& key, data->getRulebook().keys() ) {
// if( !key.isEmpty() )
// ld->DSTRuleBox->addItem( key );
// }
// /*ld->DSTLabel->setText( "<a href=\"showrules\">" + i18n("DST Rule:") + "</a>" );
// connect( ld->DSTLabel, SIGNAL( linkActivated(const QString &) ), this, SLOT( showTZRules() ) );*/
KStarsLite *kstars = KStarsLite::Instance();
kstars->qmlEngine()->rootContext()->setContextProperty("CitiesModel", &m_cityList);
//initialize cities once KStarsData finishes loading everything
connect(kstars, SIGNAL(dataLoadFinished()), this, SLOT(initCityList()));
KStarsData* data = KStarsData::Instance();
connect(data, SIGNAL(geoChanged()), this, SLOT(updateCurrentLocation()));
}
void LocationDialogLite::initCityList() {
KStarsData* data = KStarsData::Instance();
QStringList cities;
foreach ( GeoLocation *loc, data->getGeoList() )
{
QString name = loc->fullName();
cities.append( name );
filteredCityList.insert( name, loc );
//If TZ is not an even integer value, add it to listbox
/*if ( loc->TZ0() - int( loc->TZ0() ) && m_TZList.indexOf( QLocale().toString( loc->TZ0() ) ) != -1 ) {
for ( int i=0; i < m_TZList.size(); ++i ) {
if ( m_TZList[i].toDouble() > loc->TZ0() ) {
ld->TZBox->addItem( QLocale().toString( loc->TZ0() ), i-1 );
break;
}
}
}*/
}
//Sort the list of Cities alphabetically...note that filteredCityList may now have a different ordering!
m_cityList.setStringList(cities);
m_cityList.sort(0);
//ld->CountLabel->setText( i18np("One city matches search criteria","%1 cities match search criteria", ld->GeoBox->count()) );
// attempt to highlight the current kstars location in the GeoBox
/*ld->GeoBox->setCurrentItem( 0 );
for( int i=0; i < ld->GeoBox->count(); i++ ) {
if ( ld->GeoBox->item(i)->text() == data->geo()->fullName() ) {
ld->GeoBox->setCurrentRow( i );
break;
}
}*/
QStringList TZ;
for ( int i=0; i<25; ++i )
TZ.append( QLocale().toString( (double)(i-12) ) );
setProperty("TZList",TZ);
QStringList DST;
foreach( const QString& key, data->getRulebook().keys() ) {
if( !key.isEmpty() )
DST.append( key );
}
setProperty("DSTRules",DST);
}
void LocationDialogLite::filterCity(QString city, QString province, QString country) {
KStarsData* data = KStarsData::Instance();
QStringList cities;
filteredCityList.clear();
/*nameModified = false;
dataModified = false;
ld->AddCityButton->setEnabled( false );
ld->UpdateButton->setEnabled( false );*/
foreach ( GeoLocation *loc, data->getGeoList() ) {
QString sc( loc->translatedName() );
QString ss( loc->translatedCountry() );
QString sp = "";
if ( !loc->province().isEmpty() )
sp = loc->translatedProvince();
if ( sc.toLower().startsWith( city.toLower() ) &&
sp.toLower().startsWith( province.toLower() ) &&
ss.toLower().startsWith( country.toLower() ) ) {
QString name = loc->fullName();
cities.append( name );
filteredCityList.insert( name, loc );
}
}
m_cityList.setStringList(cities);
m_cityList.sort(0);
setProperty("currLocIndex", m_cityList.stringList().indexOf(m_currentLocation));
//ld->CountLabel->setText( i18np("One city matches search criteria","%1 cities match search criteria", ld->GeoBox->count()) );
}
bool LocationDialogLite::addCity(QString city, QString province, QString country, QString latitude, QString longitude, QString TimeZoneString, QString TZRule) {
QSqlDatabase mycitydb = getDB();
if( mycitydb.isValid() ) {
bool latOk(false), lngOk(false), tzOk(false);
dms lat = createDms( latitude, true, &latOk );
dms lng = createDms( longitude, true, &lngOk );
//TimeZoneString.replace( QLocale().decimalPoint(), "." );
double TZ = TimeZoneString.toDouble( &tzOk );
if ( ! latOk || ! lngOk || !tzOk) return false;
//Strip off white space
city = city.trimmed();
province = province.trimmed();
country = country.trimmed();
GeoLocation *g = NULL;
QSqlQuery add_query(mycitydb);
add_query.prepare("INSERT INTO city(Name, Province, Country, Latitude, Longitude, TZ, TZRule) VALUES(:Name, :Province, :Country, :Latitude, :Longitude, :TZ, :TZRule)");
add_query.bindValue(":Name", city);
add_query.bindValue(":Province", province);
add_query.bindValue(":Country", country);
add_query.bindValue(":Latitude", lat.toDMSString());
add_query.bindValue(":Longitude", lng.toDMSString());
add_query.bindValue(":TZ", TZ);
add_query.bindValue(":TZRule", TZRule);
if (add_query.exec() == false)
{
qWarning() << add_query.lastError() << endl;
return false;
}
//Add city to geoList
g = new GeoLocation( lng, lat, city, province, country, TZ, & KStarsData::Instance()->Rulebook[ TZRule ] );
KStarsData::Instance()->getGeoList().append(g);
mycitydb.commit();
mycitydb.close();
return true;
}
return false;
}
bool LocationDialogLite::deleteCity(QString fullName) {
QSqlDatabase mycitydb = getDB();
GeoLocation *geo = filteredCityList.value(fullName);
if( mycitydb.isValid() && geo && !geo->isReadOnly()) {
QSqlQuery delete_query(mycitydb);
delete_query.prepare("DELETE FROM city WHERE Name = :Name AND Province = :Province AND Country = :Country");
delete_query.bindValue(":Name", geo->name());
delete_query.bindValue(":Province", geo->province());
delete_query.bindValue(":Country", geo->country());
if (delete_query.exec() == false)
{
qWarning() << delete_query.lastError() << endl;
return false;
}
filteredCityList.remove(geo->fullName());
KStarsData::Instance()->getGeoList().removeOne(geo);
delete(geo);
mycitydb.commit();
mycitydb.close();
return true;
}
return false;
}
bool LocationDialogLite::editCity(QString fullName, QString city, QString province, QString country, QString latitude, QString longitude, QString TimeZoneString, QString TZRule) {
QSqlDatabase mycitydb = getDB();
GeoLocation *geo = filteredCityList.value(fullName);
KStarsData *data = KStarsData::Instance();
bool latOk(false), lngOk(false), tzOk(false);
dms lat = createDms( latitude, true, &latOk );
dms lng = createDms( longitude, true, &lngOk );
double TZ = TimeZoneString.toDouble( &tzOk );
if( mycitydb.isValid() && geo && !geo->isReadOnly() && latOk && lngOk && tzOk) {
QSqlQuery update_query(mycitydb);
update_query.prepare("UPDATE city SET Name = :newName, Province = :newProvince, Country = :newCountry, Latitude = :Latitude, Longitude = :Longitude, TZ = :TZ, TZRule = :TZRule WHERE "
"Name = :Name AND Province = :Province AND Country = :Country");
update_query.bindValue(":newName", city);
update_query.bindValue(":newProvince", province);
update_query.bindValue(":newCountry", country);
update_query.bindValue(":Name", geo->name());
update_query.bindValue(":Province", geo->province());
update_query.bindValue(":Country", geo->country());
update_query.bindValue(":Latitude", lat.toDMSString());
update_query.bindValue(":Longitude", lng.toDMSString());
update_query.bindValue(":TZ", TZ);
update_query.bindValue(":TZRule", TZRule);
if (update_query.exec() == false)
{
qWarning() << update_query.lastError() << endl;
return false;
}
geo->setName(city);
geo->setProvince(province);
geo->setCountry(country);
geo->setLat(lat);
geo->setLong(lng);
geo->setTZ(TZ);
geo->setTZRule(& KStarsData::Instance()->Rulebook[ TZRule ]);
//If we are changing current location update it
if(m_currentLocation == fullName) {
setLocation(geo->fullName());
}
mycitydb.commit();
mycitydb.close();
return true;
}
return false;
}
QString LocationDialogLite::getCity(QString fullName) {
GeoLocation *geo = filteredCityList.value(fullName);
if(geo) {
return geo->name();
}
return "";
}
QString LocationDialogLite::getProvince(QString fullName) {
GeoLocation *geo = filteredCityList.value(fullName);
if(geo) {
return geo->province();
}
return "";
}
QString LocationDialogLite::getCountry(QString fullName) {
GeoLocation *geo = filteredCityList.value(fullName);
if(geo) {
return geo->country();
}
return "";
}
double LocationDialogLite::getLatitude(QString fullName) {
GeoLocation *geo = filteredCityList.value(fullName);
if(geo) {
return geo->lat()->Degrees();
}
return 0;