Merge lp:~stellarium/stellarium/ip-query-location into lp:stellarium

Proposed by Alexander Wolf
Status: Merged
Merged at revision: 6951
Proposed branch: lp:~stellarium/stellarium/ip-query-location
Merge into: lp:stellarium
Diff against target: 1030 lines (+531/-168)
14 files modified
data/default_config.ini.cmake (+1/-1)
src/core/StelCore.cpp (+11/-2)
src/core/StelLocation.cpp (+7/-0)
src/core/StelLocation.hpp (+3/-0)
src/core/StelLocationMgr.cpp (+115/-1)
src/core/StelLocationMgr.hpp (+25/-0)
src/core/StelUtils.cpp (+34/-0)
src/core/StelUtils.hpp (+12/-0)
src/gui/LocationDialog.cpp (+122/-31)
src/gui/LocationDialog.hpp (+11/-1)
src/gui/StelGuiItems.cpp (+8/-4)
src/gui/locationDialogGui.ui (+140/-128)
src/tests/testConversions.cpp (+41/-0)
src/tests/testConversions.hpp (+1/-0)
To merge this branch: bzr merge lp:~stellarium/stellarium/ip-query-location
Reviewer Review Type Date Requested Status
Alexander Wolf Abstain
Marcos Cardinot Approve
gzotti Approve
Fabien Chéreau Pending
Review via email: mp+229834@code.launchpad.net

This proposal supersedes a proposal from 2014-07-19.

Description of the change

1) Added IP-based location query for location panel and optionally at program start.
2) Improved location GUI:
   (a) clicking on the map reduces site list to sites in 3 degrees vicinity.
   (b) selecting a country in the combo box reduces site list to sites in that country.
   (c) selecting a planet other than earth reduces site list to sites on that planet.

To post a comment you must log in.
Revision history for this message
Alexander Wolf (alexwolf) wrote : Posted in a previous version of this proposal

I checked this feature and it good work! But one moment: I think that label "IP Query" on button is not very informative and we should add tooltip and describe it.

review: Approve
Revision history for this message
Alexander Wolf (alexwolf) wrote : Posted in a previous version of this proposal

The second feature is OK for me. Are you want merge it yourself?

Revision history for this message
Alexander Wolf (alexwolf) wrote : Posted in a previous version of this proposal

Wait! What about non-Earth location?

review: Needs Fixing
Revision history for this message
Fabien Chéreau (xalioth) wrote : Posted in a previous version of this proposal
Download full text (11.0 KiB)

Hi Please cleanup The code. Also use the regular event loop to make a non
blocking call to the service.
 Le 19 juil. 2014 15:58, "Alexander Wolf" <email address hidden> a écrit :

> Alexander Wolf has proposed merging
> lp:~georg-zotti/stellarium/ip-query-location into lp:stellarium.
>
> Requested reviews:
> Alexander Wolf (alexwolf)
>
> For more details, see:
>
> https://code.launchpad.net/~georg-zotti/stellarium/ip-query-location/+merge/227418
>
> This branch introduces new feature - automatic finding approximate
> location of Stellarium from IP address.
> --
>
> https://code.launchpad.net/~georg-zotti/stellarium/ip-query-location/+merge/227418
> You are subscribed to branch lp:stellarium.
>
> === modified file 'src/core/StelCore.cpp'
> --- src/core/StelCore.cpp 2014-04-14 17:55:46 +0000
> +++ src/core/StelCore.cpp 2014-07-19 07:57:49 +0000
> @@ -114,7 +114,14 @@
> defaultLocationID =
> conf->value("init_location/location","error").toString();
> bool ok;
> StelLocationMgr* locationMgr =
> &StelApp::getInstance().getLocationMgr();
> - StelLocation location =
> locationMgr->locationForString(defaultLocationID);
> + StelLocation location;
> + if (conf->value("init_location/use_ip_geolocation_if_available",
> "false").toBool()
> + && locationMgr->ipConnectionExists())
> + {
> + location=locationMgr->locationFromIP();
> + }
> +
> + else location = locationMgr->locationForString(defaultLocationID);
> if (!location.isValid())
> {
> qWarning() << "Warning: location" << defaultLocationID <<
> "is unknown.";
>
> === modified file 'src/core/StelLocationMgr.cpp'
> --- src/core/StelLocationMgr.cpp 2014-06-12 15:47:22 +0000
> +++ src/core/StelLocationMgr.cpp 2014-07-19 07:57:49 +0000
> @@ -25,6 +25,13 @@
> #include <QDebug>
> #include <QFile>
> #include <QDir>
> +#include <QtNetwork/QNetworkInterface>
> +#include <QtNetwork/QNetworkAccessManager>
> +#include <QEventLoop>
> +#include <QNetworkRequest>
> +#include <QNetworkReply>
> +#include <QUrl>
> +#include <QUrlQuery>
>
> StelLocationMgr::StelLocationMgr()
> {
> @@ -307,3 +314,99 @@
> sourcefile.close();
> return true;
> }
> +
> +
> +//! check if there is an IP connection.
> +// Along the lines of
> +//
> http://karanbalkar.com/2014/02/detect-internet-connection-using-qt-5-framework/
> +//#define DEBUG 1
> +bool StelLocationMgr::ipConnectionExists() const
> +{
> + QList<QNetworkInterface> ifaces = QNetworkInterface::allInterfaces();
> + bool connectionExists = false;
> +
> + for (int i = 0; i < ifaces.count(); i++) {
> +
> + QNetworkInterface iface = ifaces.at(i);
> + if ( iface.flags().testFlag(QNetworkInterface::IsUp)
> + && !iface.flags().testFlag(QNetworkInterface::IsLoopBack)) {
> +
> +#ifdef DEBUG
> + // details of connection
> + qDebug() << "name:" << iface.name() << endl
> + << "mac:" << iface.hardwareAddress() << endl
> + << "ip addresses:" << endl;
> +#endif
> + for (int j=0; j<iface.addressEntries().count...

Revision history for this message
gzotti (georg-zotti) wrote : Posted in a previous version of this proposal

Hm, I was surprised that the site list mixes all sites anyhow. I will try
to reduce selection to the currently set planet...

G.

On Sa, 19.07.2014, 14:26, Alexander Wolf wrote:
> Review: Needs Fixing
>
> Wait! What about non-Earth location?
> --
> https://code.launchpad.net/~georg-zotti/stellarium/ip-query-location/+merge/227418
> You are the owner of lp:~georg-zotti/stellarium/ip-query-location.
>

Revision history for this message
Alexander Wolf (alexwolf) wrote : Posted in a previous version of this proposal

This list is "correct". I meant new features. If I change the planet and picked some point on the map (as example on Mars) then I get locations from Earth!

Revision history for this message
gzotti (georg-zotti) wrote : Posted in a previous version of this proposal

Sure. This context info did not exist previously...

I filter also by current planet name now. And I want to add a filter for
country as next step towards better usability.

G.

On Sa, 19.07.2014, 18:42, Alexander Wolf wrote:
> This list is "correct". I meant new features. If I change the planet and
> picked some point on the map (as example on Mars) then I get locations
> from Earth!
> --
> https://code.launchpad.net/~georg-zotti/stellarium/ip-query-location/+merge/227418
> You are the owner of lp:~georg-zotti/stellarium/ip-query-location.
>

Revision history for this message
Alexander Wolf (alexwolf) wrote : Posted in a previous version of this proposal

2014-07-20 1:33 GMT+07:00 gzotti <email address hidden>:

> Sure. This context info did not exist previously...
>
> I filter also by current planet name now. And I want to add a filter for
> country as next step towards better usability.
>

It's introduces important problem: search tool will search location in full
list or in filtered list?

--
With best regards, Alexander

Revision history for this message
gzotti (georg-zotti) wrote : Posted in a previous version of this proposal

The list box gets filled with a preselected short list of nearby locations
on the current planet. If the user selects Earth, the complete list will
be shown at the moment (50 non-Earth entries in 15000 locations, should
not matter...)

The search tool is directly connected to the list, so it only searches in
the pre-filtered list.

There is a reset list button to recreate all entries.

I am not yet sure if I shouldn't clear out the country combobox if
planet!=Earth. This was always quite strange...

G.

On Sa, 19.07.2014, 20:45, Alexander Wolf wrote:
> 2014-07-20 1:33 GMT+07:00 gzotti <email address hidden>:
>
>> Sure. This context info did not exist previously...
>>
>> I filter also by current planet name now. And I want to add a filter for
>> country as next step towards better usability.
>>
>
> It's introduces important problem: search tool will search location in
> full
> list or in filtered list?
>
> --
> With best regards, Alexander
>
> https://code.launchpad.net/~georg-zotti/stellarium/ip-query-location/+merge/227418
> You are the owner of lp:~georg-zotti/stellarium/ip-query-location.
>

Revision history for this message
gzotti (georg-zotti) wrote : Posted in a previous version of this proposal

I have added the requested improvements. I think it works all now.

review: Needs Resubmitting
Revision history for this message
Alexander Wolf (alexwolf) wrote : Posted in a previous version of this proposal

OK. It work correct now and I think it ready to merge. Fabien?

review: Approve
Revision history for this message
Fabien Chéreau (xalioth) wrote : Posted in a previous version of this proposal

Please see comments

review: Needs Fixing
Revision history for this message
Marcos Cardinot (cardinot) wrote : Posted in a previous version of this proposal

Hello Georg,
congrats for the excellent work!
I have just a couple of things to suggest (nitpicks)... see comments + I noticed that you are using spaces instead of tabs...

review: Needs Fixing
Revision history for this message
Marcos Cardinot (cardinot) : Posted in a previous version of this proposal
review: Approve
Revision history for this message
gzotti (georg-zotti) wrote : Posted in a previous version of this proposal
Download full text (19.3 KiB)

Dear Fabien,

I fixed these items on Monday. Do you approve a merge now?

Kind regards,
Georg

On Mo, 21.07.2014, 19:07, Fabien Chéreau wrote:
> Review: Needs Fixing
>
> Please see comments
>
> Diff comments:
>
>> === modified file 'src/core/StelCore.cpp'
>> --- src/core/StelCore.cpp 2014-04-14 17:55:46 +0000
>> +++ src/core/StelCore.cpp 2014-07-20 13:42:31 +0000
>> @@ -114,7 +114,13 @@
>> defaultLocationID =
>> conf->value("init_location/location","error").toString();
>> bool ok;
>> StelLocationMgr* locationMgr =
>> &StelApp::getInstance().getLocationMgr();
>> - StelLocation location =
>> locationMgr->locationForString(defaultLocationID);
>> + StelLocation location;
>> + if (conf->value("init_location/use_ip_geolocation_if_available",
>> "false").toBool())
>> + {
>> + locationMgr->locationFromIP();
>> + }
>> +
>> + else location = locationMgr->locationForString(defaultLocationID);
>> if (!location.isValid())
>> {
>> qWarning() << "Warning: location" << defaultLocationID << "is
>> unknown.";
>>
>> === modified file 'src/core/StelLocation.cpp'
>> --- src/core/StelLocation.cpp 2014-02-15 15:37:23 +0000
>> +++ src/core/StelLocation.cpp 2014-07-20 13:42:31 +0000
>> @@ -125,3 +125,10 @@
>> return loc;
>> }
>>
>> +// Compute great-circle distance between two locations
>> +float StelLocation::distanceDegrees(const float long1, const float
>> lat1, const float long2, const float lat2)
>> +{
>> + const float DEGREES=M_PI/180.0f;
>> + return std::acos( std::sin(lat1*DEGREES)*std::sin(lat2*DEGREES) +
>> +
>> std::cos(lat1*DEGREES)*std::cos(lat2*DEGREES)*std::cos((long1-long2)*DEGREES)
>> ) / DEGREES;
>> +}
>>
>> === modified file 'src/core/StelLocation.hpp'
>> --- src/core/StelLocation.hpp 2014-04-15 17:10:07 +0000
>> +++ src/core/StelLocation.hpp 2014-07-20 13:42:31 +0000
>> @@ -74,6 +74,9 @@
>> //! Parse a location from a line serialization
>> static StelLocation createFromLine(const QString& line);
>>
>> + //! Compute great-circle distance between two locations
>> + static float distanceDegrees(const float long1, const float lat1,
>> const float long2, const float lat2);
>> +
>> //! Used privately by the StelLocationMgr
>> bool isUserLocation;
>>
>>
>> === modified file 'src/core/StelLocationMgr.cpp'
>> --- src/core/StelLocationMgr.cpp 2014-06-12 15:47:22 +0000
>> +++ src/core/StelLocationMgr.cpp 2014-07-20 13:42:31 +0000
>> @@ -17,6 +17,7 @@
>> */
>>
>> #include "StelApp.hpp"
>> +#include "StelCore.hpp"
>> #include "StelFileMgr.hpp"
>> #include "StelLocationMgr.hpp"
>> #include "StelUtils.hpp"
>> @@ -25,6 +26,12 @@
>> #include <QDebug>
>> #include <QFile>
>> #include <QDir>
>> +#include <QtNetwork/QNetworkInterface>
>> +#include <QtNetwork/QNetworkAccessManager>
>> +#include <QNetworkRequest>
>> +#include <QNetworkReply>
>> +#include <QUrl>
>> +#include <QUrlQuery>
>>
>> StelLocationMgr::StelLocationMgr()
>> {
>> @@ -36,9 +43,12 @@
>>
>> modelAllLocation = new QStringListModel(this);
>> modelAllLocation->setStringList(locations.keys());
>> + modelPickedLocation = new QStringListModel(this); // keep empty for
>> now.
>>
>> // Init to Paris France because it's the center of the world.
>> lastResortLocation =...

Revision history for this message
Fabien Chéreau (xalioth) wrote : Posted in a previous version of this proposal
Download full text (22.3 KiB)

Hi Georg,

now that I'm back from holidays, I could acutally try the code, and I have
some more general comments about your (very very good!) work:

 - we should rename "IP Query" to something less technical, like "Get
location from Network"

 - I think the IP location is such an improvement that it should be the
default for all new install, and also probably used by default for installs
where the location was never set (set to Paris). This would imply that we
transform at startup all older config.ini from location = Paris, France to
location = auto. And use this "auto" value to trigger IP Lookup instead of
adding a new "init_location/use_ip_geolocation_if_available" key.

- Also when the lookup is successful, we could save the last know location
into an "init_location/last_resort_location" for the next time we start
without network.

Sorry to give these feedbacks so late, I hope they make sense, what do you
think? In any case, I think the lack of auto location feature was the most
annoying problem of Stellarium for an average user living in US, so thanks
a lot again!

Fabien

On Sat, Jul 26, 2014 at 12:24 PM, gzotti <email address hidden> wrote:

> Dear Fabien,
>
> I fixed these items on Monday. Do you approve a merge now?
>
> Kind regards,
> Georg
>
> On Mo, 21.07.2014, 19:07, Fabien Chéreau wrote:
> > Review: Needs Fixing
> >
> > Please see comments
> >
> > Diff comments:
> >
> >> === modified file 'src/core/StelCore.cpp'
> >> --- src/core/StelCore.cpp 2014-04-14 17:55:46 +0000
> >> +++ src/core/StelCore.cpp 2014-07-20 13:42:31 +0000
> >> @@ -114,7 +114,13 @@
> >> defaultLocationID =
> >> conf->value("init_location/location","error").toString();
> >> bool ok;
> >> StelLocationMgr* locationMgr =
> >> &StelApp::getInstance().getLocationMgr();
> >> - StelLocation location =
> >> locationMgr->locationForString(defaultLocationID);
> >> + StelLocation location;
> >> + if (conf->value("init_location/use_ip_geolocation_if_available",
> >> "false").toBool())
> >> + {
> >> + locationMgr->locationFromIP();
> >> + }
> >> +
> >> + else location = locationMgr->locationForString(defaultLocationID);
> >> if (!location.isValid())
> >> {
> >> qWarning() << "Warning: location" << defaultLocationID <<
> "is
> >> unknown.";
> >>
> >> === modified file 'src/core/StelLocation.cpp'
> >> --- src/core/StelLocation.cpp 2014-02-15 15:37:23 +0000
> >> +++ src/core/StelLocation.cpp 2014-07-20 13:42:31 +0000
> >> @@ -125,3 +125,10 @@
> >> return loc;
> >> }
> >>
> >> +// Compute great-circle distance between two locations
> >> +float StelLocation::distanceDegrees(const float long1, const float
> >> lat1, const float long2, const float lat2)
> >> +{
> >> + const float DEGREES=M_PI/180.0f;
> >> + return std::acos( std::sin(lat1*DEGREES)*std::sin(lat2*DEGREES) +
> >> +
> >>
> std::cos(lat1*DEGREES)*std::cos(lat2*DEGREES)*std::cos((long1-long2)*DEGREES)
> >> ) / DEGREES;
> >> +}
> >>
> >> === modified file 'src/core/StelLocation.hpp'
> >> --- src/core/StelLocation.hpp 2014-04-15 17:10:07 +0000
> >> +++ src/core/StelLocation.hpp 2014-07-20 13:42:31 +0000
> >> ...

Revision history for this message
gzotti (georg-zotti) wrote : Posted in a previous version of this proposal
Download full text (3.3 KiB)

Dear Fabien,

thanks for your friendly words.

I know "IP query" is very technical. But what to write on a 6-letter
button? Else, the button must stretch over the whole window, I did not
want to make it too intrusive. If there is space, it should be
"approximate location", my own query is about 50km off... But it's still
quite a good start.

A default IP lookup for new installs seems fine, as long as there remains
a fallback location in case someone travels to his offline PC with an USB
stick with the latest version. (When I traveled to Namibia for some
astrophotos with a Stellarium-guided telescope, my Atom netbook was also
definitely offline...)

Having the always-auto-lookup-at-start feature is OK. But It must be
possible to set and keep a home position as well, even if we are online at
startup. (And if somebody in Paris is happy with startup location, he will
be surprised to find his place renamed to IPxxxx :-)

The other changes are with finding a location near map-click point and
with the country/planet comboboxes. I think they are much more functional
now. What may still be done is to deactivate and empty the country box if
we are not on Earth.

My short slot of time is unfortunately over for this weekend. So, if you
like it, please merge and feel free to tweak these small details.

I just tried your brother's no-bit-field branch. It compiles on my Atom
450 netbook (MSVC2012/Angle; takes ages...), but the shader programs are
too long. I cannot find any info on how to programmatically check shader
support from the GPU: is Angle limited to pixelshader2, vertexshader2 and
fails on every system, or would it compile ps_3, vs_3 if the graphics card
supports this? Going for Angle was the hope to support simpler/older
hardware, so if there would be a way to support ps_2+vs_2 hardware like
Atom or older Radeon or Intel GMA by utilizing simpler shader programs
(e.g. no ring shadows, normal maps, etc.?) after some tests, there would
be less users having to use super-slow MESA. (But I'm happy at least MESA
is a stable fallback...)

What I still don't know is why my both NVidias on WinXP fail. Both should
support OpenGL3.3.

Kind regards,
Georg

On Sa, 26.07.2014, 18:24, Fabien Chéreau wrote:
> Hi Georg,
>
> now that I'm back from holidays, I could acutally try the code, and I have
> some more general comments about your (very very good!) work:
>
> - we should rename "IP Query" to something less technical, like "Get
> location from Network"
>
> - I think the IP location is such an improvement that it should be the
> default for all new install, and also probably used by default for
> installs
> where the location was never set (set to Paris). This would imply that we
> transform at startup all older config.ini from location = Paris, France to
> location = auto. And use this "auto" value to trigger IP Lookup instead of
> adding a new "init_location/use_ip_geolocation_if_available" key.
>
> - Also when the lookup is successful, we could save the last know location
> into an "init_location/last_resort_location" for the next time we start
> without network.
>
> Sorry to give these feedbacks so late, I hope they make sense, what do you
> think? In ...

Read more...

Revision history for this message
Alexander Wolf (alexwolf) wrote : Posted in a previous version of this proposal

IMHO we can merge this branch and improve some features.

Revision history for this message
Alexander Wolf (alexwolf) wrote : Posted in a previous version of this proposal

OK. I updated code to usage of this feature by default.

Revision history for this message
Alexander Wolf (alexwolf) :
review: Approve
Revision history for this message
gzotti (georg-zotti) wrote :

Hmm, if

in current merge/diff display, Line 27: (defaultLocation.contains("auto"))...

consider a (existence unknown to me) a place name "Antautorina", you never know what placenames exist... ;-) --> Should be ".equals()"

One place of even greater concern, but I did not test your changes of today:

line 183: setting Last_resort_location: at this point the newly looked-up often has empty placename/country (or just IPXXX.YYY.ZZZ.AAA). On startup without IP connection and "auto" setting, this would mean looking up IPXXX.YYY.ZZZ.AAA in the location list, which will likely fail, or not? last_resort should really be that, a location guaranteed to exist in the location database. Have you tested what happens then?

review: Needs Fixing
6938. By Alexander Wolf

avoid Antautorina's bug

6939. By Alexander Wolf

avoid unknown location's bug (location not exists in stellarium database)

Revision history for this message
Alexander Wolf (alexwolf) wrote :

OK. I fixed both issues.

Revision history for this message
gzotti (georg-zotti) wrote :

Some more usability things:

config.ini, name "last_resort_location" is incomprehensible to users. Rename to last_location.

I tried: switch off LAN, start without config.ini. It loads, displays 0.00/0.00 for a second, then goes to Paris. OK.

switch on LAN, start. IP lookup, correctly displaying even place name (this time IP answer was more complete than at my place.)

restart Stellarium, name lookup of course again leads to correct display.

switch off LAN, restart Stellarium, loads coordinates of last[_resort?!]_location correctly (Location on map was OK), but displays bogus placename, consisting of degrees without any connection to the stored or used location. Name should show coordinates in this case, IMHO.

Also, I think that after the first successful IP lookup, this function should be off by default. Else we may put too much traffic onto the free service, and/or people may even complain about unwanted network traffic (?), but this is my opinion only. What do the others say?

review: Needs Fixing
Revision history for this message
Alexander Wolf (alexwolf) wrote :

> switch off LAN, restart Stellarium, loads coordinates of last[_resort?!]_location correctly (Location on map was OK), but displays bogus placename, consisting of degrees without any connection to the stored or used location. Name should show coordinates in this case, IMHO.

In last_resort_location stored coordinates of last location, because name of this location may be not exists in our database.

6940. By Alexander Wolf

renamed last_resort_location to last_location

Revision history for this message
gzotti (georg-zotti) wrote :

Sure, but the displayed name is random numbers, not the coordinates used!

Example: The stored last_[remove"resort_"]location = 48.2, 16.23
Displayed in lower left corner: Earth, 147°23' 133°34'

(I did not copy these numbers from live display, but this should just
illustrate their randomness. No connection I can see with the real data.)

Revision history for this message
Alexander Wolf (alexwolf) wrote :

Oh, yes! I'll look it tomorrow.

6941. By Alexander Wolf

fixed issue of display coordinates of location

Revision history for this message
Alexander Wolf (alexwolf) wrote :

OK. It's done.

Revision history for this message
gzotti (georg-zotti) wrote :

OK, looks fine now.

review: Approve
6942. By Alexander Wolf

avoid rounding issue and extend unit tests

Revision history for this message
Alexander Wolf (alexwolf) wrote :

Fabien, please review this code.

Revision history for this message
Marcos Cardinot (cardinot) wrote :

I have just a small suggestion, IMHO the button "Return to default location" should be placed on the left side, above "Use current location as default"... it means put the horizontalSpacer between "Delete" and "Return to default location"...

review: Approve
Revision history for this message
Alexander Wolf (alexwolf) :
review: Abstain

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'data/default_config.ini.cmake'
2--- data/default_config.ini.cmake 2014-07-31 19:02:38 +0000
3+++ data/default_config.ini.cmake 2014-08-08 12:24:49 +0000
4@@ -242,7 +242,7 @@
5 nebula_magnitude_limit = 8.5
6
7 [init_location]
8-location = Paris, France
9+location = auto
10 landscape_name = guereins
11
12 [files]
13
14=== modified file 'src/core/StelCore.cpp'
15--- src/core/StelCore.cpp 2014-04-14 17:55:46 +0000
16+++ src/core/StelCore.cpp 2014-08-08 12:24:49 +0000
17@@ -111,10 +111,19 @@
18 {
19 QSettings* conf = StelApp::getInstance().getSettings();
20
21- defaultLocationID = conf->value("init_location/location","error").toString();
22+ defaultLocationID = conf->value("init_location/location", "auto").toString();
23 bool ok;
24 StelLocationMgr* locationMgr = &StelApp::getInstance().getLocationMgr();
25- StelLocation location = locationMgr->locationForString(defaultLocationID);
26+ StelLocation location;
27+ if (defaultLocationID == "auto")
28+ {
29+ locationMgr->locationFromIP();
30+ }
31+ else
32+ {
33+ location = locationMgr->locationForString(defaultLocationID);
34+ }
35+
36 if (!location.isValid())
37 {
38 qWarning() << "Warning: location" << defaultLocationID << "is unknown.";
39
40=== modified file 'src/core/StelLocation.cpp'
41--- src/core/StelLocation.cpp 2014-02-15 15:37:23 +0000
42+++ src/core/StelLocation.cpp 2014-08-08 12:24:49 +0000
43@@ -125,3 +125,10 @@
44 return loc;
45 }
46
47+// Compute great-circle distance between two locations
48+float StelLocation::distanceDegrees(const float long1, const float lat1, const float long2, const float lat2)
49+{
50+ const float DEGREES=M_PI/180.0f;
51+ return std::acos( std::sin(lat1*DEGREES)*std::sin(lat2*DEGREES) +
52+ std::cos(lat1*DEGREES)*std::cos(lat2*DEGREES)*std::cos((long1-long2)*DEGREES) ) / DEGREES;
53+}
54
55=== modified file 'src/core/StelLocation.hpp'
56--- src/core/StelLocation.hpp 2014-04-15 17:10:07 +0000
57+++ src/core/StelLocation.hpp 2014-08-08 12:24:49 +0000
58@@ -74,6 +74,9 @@
59 //! Parse a location from a line serialization
60 static StelLocation createFromLine(const QString& line);
61
62+ //! Compute great-circle distance between two locations
63+ static float distanceDegrees(const float long1, const float lat1, const float long2, const float lat2);
64+
65 //! Used privately by the StelLocationMgr
66 bool isUserLocation;
67
68
69=== modified file 'src/core/StelLocationMgr.cpp'
70--- src/core/StelLocationMgr.cpp 2014-06-12 15:47:22 +0000
71+++ src/core/StelLocationMgr.cpp 2014-08-08 12:24:49 +0000
72@@ -17,6 +17,7 @@
73 */
74
75 #include "StelApp.hpp"
76+#include "StelCore.hpp"
77 #include "StelFileMgr.hpp"
78 #include "StelLocationMgr.hpp"
79 #include "StelUtils.hpp"
80@@ -25,9 +26,18 @@
81 #include <QDebug>
82 #include <QFile>
83 #include <QDir>
84+#include <QtNetwork/QNetworkInterface>
85+#include <QtNetwork/QNetworkAccessManager>
86+#include <QNetworkRequest>
87+#include <QNetworkReply>
88+#include <QUrl>
89+#include <QUrlQuery>
90+#include <QSettings>
91
92 StelLocationMgr::StelLocationMgr()
93 {
94+ QSettings* conf = StelApp::getInstance().getSettings();
95+
96 // The line below allows to re-generate the location file, you still need to gunzip it manually afterward.
97 // generateBinaryLocationFile("data/base_locations.txt", false, "data/base_locations.bin");
98
99@@ -36,9 +46,10 @@
100
101 modelAllLocation = new QStringListModel(this);
102 modelAllLocation->setStringList(locations.keys());
103+ modelPickedLocation = new QStringListModel(this); // keep empty for now.
104
105 // Init to Paris France because it's the center of the world.
106- lastResortLocation = locationForString("Paris, France");
107+ lastResortLocation = locationForString(conf->value("init_location/last_location", "Paris, France").toString());
108 }
109
110 void StelLocationMgr::generateBinaryLocationFile(const QString& fileName, bool isUserLocation, const QString& binFilePath) const
111@@ -144,6 +155,10 @@
112
113 StelLocationMgr::~StelLocationMgr()
114 {
115+ delete modelPickedLocation;
116+ modelPickedLocation=NULL;
117+ delete modelAllLocation;
118+ modelAllLocation=NULL;
119 }
120
121 static float parseAngle(const QString& s, bool* ok)
122@@ -307,3 +322,102 @@
123 sourcefile.close();
124 return true;
125 }
126+
127+// lookup location from IP address.
128+void StelLocationMgr::locationFromIP()
129+{
130+ QNetworkRequest req( QUrl( QString("http://freegeoip.net/csv/") ) );
131+ networkReply=StelApp::getInstance().getNetworkAccessManager()->get(req);
132+ connect(networkReply, SIGNAL(finished()), this, SLOT(changeLocationFromNetworkLookup()));
133+}
134+
135+// slot that receives IP-based location data from the network.
136+void StelLocationMgr::changeLocationFromNetworkLookup()
137+{
138+ StelLocation location;
139+ StelCore *core=StelApp::getInstance().getCore();
140+ if (networkReply->error() == QNetworkReply::NoError) {
141+ //success
142+ // Tested with and without working network connection.
143+ QByteArray answer=networkReply->readAll();
144+ // answer/splitline example: "222.222.222.222","AT","Austria","","","","","47.3333","13.3333","",""
145+ // The parts from freegeoip are: ip,country_code,country_name,region_code,region_name,city,zipcode,latitude,longitude,metro_code,area_code
146+ // longitude and latitude should always be filled.
147+ // A few tests:
148+ if ((answer.count('"') != 22 ) || (answer.count(',') != 10 ))
149+ {
150+ qDebug() << "StelLocationMgr: Malformatted answer in IP-based location lookup: \n\t" << answer;
151+ qDebug() << "StelLocationMgr: Will not change location.";
152+ networkReply->deleteLater();
153+ return;
154+ }
155+ const QStringList& splitline = QString(answer).split(",");
156+ if (splitline.count() != 11 )
157+ {
158+ qDebug() << "StelLocationMgr: Unexpected answer in IP-based location lookup: \n\t" << answer;
159+ qDebug() << "StelLocationMgr: Will not change location.";
160+ networkReply->deleteLater();
161+ return;
162+ }
163+ if ((splitline.at(7)=="\"\"") || (splitline.at(8)=="\"\"")) // empty coordinates?
164+ {
165+ qDebug() << "StelLocationMgr: Invalid coordinates from IP-based lookup. Ignoring: \n\t" << answer;
166+ networkReply->deleteLater();
167+ return;
168+ }
169+ float latitude=splitline.at(7).mid(1, splitline.at(7).length()-2).toFloat();
170+ float longitude=splitline.at(8).mid(1, splitline.at(8).length()-2).toFloat();
171+ QString locLine= // we re-pack into a new line that will be parsed back by StelLocation...
172+ QString("%1\t%2\t%3\t%4\t%5\t%6\t%7\t0")
173+ .arg(splitline.at(5).length()>2 ? splitline.at(5).mid(1, splitline.at(5).length()-2) : QString("IP%1").arg(splitline.at(0).mid(1, splitline.at(0).length()-2)))
174+ .arg(splitline.at(4).length()>2 ? splitline.at(4).mid(1, splitline.at(4).length()-2) : "IPregion")
175+ .arg(splitline.at(2).length()>2 ? splitline.at(2).mid(1, splitline.at(2).length()-2) : "IPcountry") // country
176+ .arg("X") // role: X=user-defined
177+ .arg(0) // population: unknown
178+ .arg(latitude<0 ? QString("%1S").arg(-latitude, 0, 'f', 6) : QString("%1N").arg(latitude, 0, 'f', 6))
179+ .arg(longitude<0 ? QString("%1W").arg(-longitude, 0, 'f', 6) : QString("%1E").arg(longitude, 0, 'f', 6));
180+ location=StelLocation::createFromLine(locLine); // in lack of a regular constructor ;-)
181+ core->moveObserverTo(location, 0.0f, 0.0f);
182+ QSettings* conf = StelApp::getInstance().getSettings();
183+ conf->setValue("init_location/last_location", QString("%1, %2").arg(latitude).arg(longitude));
184+ }
185+ else
186+ {
187+ qDebug() << "Failure getting IP-based location: \n\t" <<networkReply->errorString();
188+ core->moveObserverTo(lastResortLocation, 0.0f, 0.0f);
189+ }
190+ networkReply->deleteLater();
191+}
192+
193+void StelLocationMgr::pickLocationsNearby(const QString planetName, const float longitude, const float latitude, const float radiusDegrees)
194+{
195+ pickedLocations.clear();
196+ QMapIterator<QString, StelLocation> iter(locations);
197+ while (iter.hasNext())
198+ {
199+ iter.next();
200+ const StelLocation *loc=&iter.value();
201+ if ( (loc->planetName == planetName) &&
202+ (StelLocation::distanceDegrees(longitude, latitude, loc->longitude, loc->latitude) <= radiusDegrees) )
203+ {
204+ pickedLocations.insert(iter.key(), iter.value());
205+ }
206+ }
207+ modelPickedLocation->setStringList(pickedLocations.keys());
208+}
209+
210+void StelLocationMgr::pickLocationsInCountry(const QString country)
211+{
212+ pickedLocations.clear();
213+ QMapIterator<QString, StelLocation> iter(locations);
214+ while (iter.hasNext())
215+ {
216+ iter.next();
217+ const StelLocation *loc=&iter.value();
218+ if (loc->country == country)
219+ {
220+ pickedLocations.insert(iter.key(), iter.value());
221+ }
222+ }
223+ modelPickedLocation->setStringList(pickedLocations.keys());
224+}
225
226=== modified file 'src/core/StelLocationMgr.hpp'
227--- src/core/StelLocationMgr.hpp 2013-10-14 07:43:06 +0000
228+++ src/core/StelLocationMgr.hpp 2014-08-08 12:24:49 +0000
229@@ -26,6 +26,7 @@
230 #include <QMap>
231
232 class QStringListModel;
233+class QNetworkReply;
234
235 //! @class StelLocationMgr
236 //! Manage the list of available location.
237@@ -41,6 +42,8 @@
238
239 //! Return the model containing all the city
240 QStringListModel* getModelAll() {return modelAllLocation;}
241+ //! Return the model containing picked (nearby) cities or cities from a single country, or other preselection.
242+ QStringListModel* getModelPicked() {return modelPickedLocation;}
243
244 //! Return the list of all loaded locations
245 QList<StelLocation> getAll() const {return locations.values();}
246@@ -70,6 +73,20 @@
247 //! @param id the location ID
248 bool deleteUserLocation(const QString& id);
249
250+ //! Find location via online lookup of IP address
251+ void locationFromIP();
252+
253+ //! Preselect list of locations within @param radiusDegrees of selected (usually screen-clicked) coordinates.
254+ //! The list can be retrieved by calling @name getModelPicked().
255+ void pickLocationsNearby(const QString planetName, const float longitude, const float latitude, const float radiusDegrees);
256+ //! Preselect list of locations in a particular country only.
257+ //! The list can be retrieved by calling @name getModelPicked().
258+ void pickLocationsInCountry(const QString country);
259+
260+public slots:
261+ //! Process answer from online lookup of IP address
262+ void changeLocationFromNetworkLookup();
263+
264 private:
265 void generateBinaryLocationFile(const QString& txtFile, bool isUserLocation, const QString& binFile) const;
266
267@@ -79,11 +96,19 @@
268
269 //! Model containing all the city information
270 QStringListModel* modelAllLocation;
271+ //! Model containing selected city information
272+ QStringListModel* modelPickedLocation;
273
274 //! The list of all loaded locations
275 QMap<QString, StelLocation> locations;
276+ //! A list of locations generated on-the-fly by filtering from @name locations
277+ QMap<QString, StelLocation> pickedLocations;
278
279 StelLocation lastResortLocation;
280+
281+ //! For IP-based location lookup
282+ QNetworkReply *networkReply;
283+
284 };
285
286 #endif // _STELLOCATIONMGR_HPP_
287
288=== modified file 'src/core/StelUtils.cpp'
289--- src/core/StelUtils.cpp 2014-07-05 15:16:58 +0000
290+++ src/core/StelUtils.cpp 2014-08-08 12:24:49 +0000
291@@ -370,6 +370,40 @@
292 return str;
293 }
294
295+void decDegToDms(double angle, bool &sign, unsigned int &d, unsigned int &m, double &s)
296+{
297+ sign = true;
298+ if (angle<0.)
299+ {
300+ sign = false;
301+ angle *= -1;
302+ }
303+
304+ d = (unsigned int)angle;
305+ m = (unsigned int)((angle-d)*60);
306+ s = (angle-d)*3600.-60.*m;
307+
308+ if (s==60.)
309+ {
310+ s = 0.;
311+ m += 1;
312+ }
313+ if (m==60)
314+ {
315+ m = 0;
316+ d += 1;
317+ }
318+}
319+
320+// Convert an angle in decimal degrees to a dms formatted string
321+QString decDegToDmsStr(const double angle)
322+{
323+ bool sign;
324+ double s;
325+ unsigned int d, m;
326+ decDegToDms(angle, sign, d, m, s);
327+ return QString("%1%2%3%4\'%5\"").arg(sign?'+':'-').arg(d).arg(QChar(0x00B0)).arg(m,2,10,QLatin1Char('0')).arg((unsigned int)s,2,10,QLatin1Char('0'));
328+}
329
330 // Convert a dms formatted string to an angle in radian
331 double dmsStrToRad(const QString& s)
332
333=== modified file 'src/core/StelUtils.hpp'
334--- src/core/StelUtils.hpp 2014-06-22 14:08:40 +0000
335+++ src/core/StelUtils.hpp 2014-08-08 12:24:49 +0000
336@@ -99,6 +99,18 @@
337 //! @param decimal output decimal second value
338 QString radToDmsStr(const double angle, const bool decimal=false, const bool useD=false);
339
340+ //! Convert an angle in decimal degree to +-dms format.
341+ //! @param angle input angle in decimal degree
342+ //! @param sign true if positive, false otherwise
343+ //! @param d degree component
344+ //! @param m minute component
345+ //! @param s second component
346+ void decDegToDms(double angle, bool& sign, unsigned int& d, unsigned int& m, double& s);
347+
348+ //! Convert an angle in decimal degrees to a dms formatted string.
349+ //! @param angle input angle in decimal degrees
350+ QString decDegToDmsStr(const double angle);
351+
352 //! Convert a dms formatted string to an angle in radian
353 //! @param s The input string
354 double dmsStrToRad(const QString& s);
355
356=== modified file 'src/gui/LocationDialog.cpp'
357--- src/gui/LocationDialog.cpp 2014-03-21 18:03:55 +0000
358+++ src/gui/LocationDialog.cpp 2014-08-08 12:24:49 +0000
359@@ -99,22 +99,30 @@
360 connect(ui->mapLabel, SIGNAL(positionChanged(double, double)), this, SLOT(setPositionFromMap(double, double)));
361
362 connect(ui->addLocationToListPushButton, SIGNAL(clicked()), this, SLOT(addCurrentLocationToList()));
363- connect(ui->deleteLocationFromListPushButton, SIGNAL(clicked()), this, SLOT(deleteCurrentLocationFromList()));
364+ connect(ui->deleteLocationFromListPushButton, SIGNAL(clicked()), this, SLOT(deleteCurrentLocationFromList()));
365+ connect(ui->resetListPushButton, SIGNAL(clicked()), this, SLOT(resetCompleteList()));
366+ connect(ui->countryNameComboBox, SIGNAL(activated(const QString &)), this, SLOT(filterSitesByCountry()));
367
368 StelCore* core = StelApp::getInstance().getCore();
369 const StelLocation& currentLocation = core->getCurrentLocation();
370+ bool b = (currentLocation.getID() == core->getDefaultLocationID());
371+ QSettings* conf = StelApp::getInstance().getSettings();
372+ if (conf->value("init_location/location", "auto").toString() == "auto")
373+ {
374+ ui->useIpQueryCheckBox->setChecked(true);
375+ b = false;
376+ }
377+
378 setFieldsFromLocation(currentLocation);
379-
380- const bool b = (currentLocation.getID() == core->getDefaultLocationID());
381 updateDefaultLocationControls(b);
382- connect(ui->useAsDefaultLocationCheckBox, SIGNAL(clicked()), this, SLOT(setDefaultLocation()));
383- connect(ui->pushButtonReturnToDefault, SIGNAL(clicked()),
384- core, SLOT(returnToDefaultLocation()));
385+
386+ connect(ui->useIpQueryCheckBox, SIGNAL(clicked(bool)), this, SLOT(ipQueryLocation(bool)));
387+ connect(ui->useAsDefaultLocationCheckBox, SIGNAL(clicked(bool)), this, SLOT(setDefaultLocation(bool)));
388+ connect(ui->pushButtonReturnToDefault, SIGNAL(clicked()), core, SLOT(returnToDefaultLocation()));
389
390 connectEditSignals();
391
392- connect(core, SIGNAL(locationChanged(StelLocation)),
393- this, SLOT(updateFromProgram(StelLocation)));
394+ connect(core, SIGNAL(locationChanged(StelLocation)), this, SLOT(updateFromProgram(StelLocation)));
395
396 ui->citySearchLineEdit->setFocus();
397 }
398@@ -138,7 +146,12 @@
399 // Check that the use as default check box needs to be updated
400 // Move to setFieldsFromLocation()? --BM?
401 const bool b = currentLocation.getID() == stelCore->getDefaultLocationID();
402- updateDefaultLocationControls(b);
403+ QSettings* conf = StelApp::getInstance().getSettings();
404+ if (conf->value("init_location/location", "auto").toString() != ("auto"))
405+ {
406+ updateDefaultLocationControls(b);
407+ ui->pushButtonReturnToDefault->setEnabled(!b);
408+ }
409
410 const QString& key1 = currentLocation.getID();
411 const QString& key2 = locationFromFields().getID();
412@@ -169,8 +182,7 @@
413 disconnect(ui->countryNameComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(reportEdit()));
414 // Why an edit should be reported even if the country is not changed? --BM
415 //disconnect(ui->countryNameComboBox, SIGNAL(activated(const QString&)), this, SLOT(comboBoxChanged(const QString&)));
416- disconnect(ui->cityNameLineEdit, SIGNAL(textEdited(const QString&)),
417- this, SLOT(reportEdit()));
418+ disconnect(ui->cityNameLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(reportEdit()));
419 }
420
421 void LocationDialog::connectEditSignals()
422@@ -182,8 +194,7 @@
423 connect(ui->countryNameComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(reportEdit()));
424 // Why an edit should be reported even if the country is not changed? --BM
425 //connect(ui->countryNameComboBox, SIGNAL(activated(const QString&)), this, SLOT(comboBoxChanged(const QString&)));
426- connect(ui->cityNameLineEdit, SIGNAL(textEdited(const QString&)),
427- this, SLOT(reportEdit()));
428+ connect(ui->cityNameLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(reportEdit()));
429 }
430
431 void LocationDialog::setFieldsFromLocation(const StelLocation& loc)
432@@ -235,7 +246,7 @@
433 // Update the map for the given location.
434 void LocationDialog::setMapForLocation(const StelLocation& loc)
435 {
436- // Avoids usless processing
437+ // Avoids useless processing
438 if (lastPlanet==loc.planetName)
439 return;
440
441@@ -358,6 +369,15 @@
442 loc.longitude = longitude;
443 setFieldsFromLocation(loc);
444 StelApp::getInstance().getCore()->moveObserverTo(loc, 0.);
445+ // GZ: Filter location list for nearby sites. I assume Earth locations are better known. With only few locations on other planets in the list, 30 degrees seem OK.
446+ StelApp::getInstance().getLocationMgr().pickLocationsNearby(loc.planetName, longitude, latitude, loc.planetName=="Earth" ? 3.0f: 30.0f);
447+ QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(this);
448+ proxyModel->setSourceModel((QAbstractItemModel*)StelApp::getInstance().getLocationMgr().getModelPicked());
449+ proxyModel->sort(0, Qt::AscendingOrder);
450+ proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
451+ ui->citiesListView->setModel(proxyModel);
452+ ui->citySearchLineEdit->clear();
453+ connect(ui->citySearchLineEdit, SIGNAL(textChanged(const QString&)), proxyModel, SLOT(setFilterWildcard(const QString&)));
454 }
455
456 // Called when the planet name is changed by hand
457@@ -380,6 +400,24 @@
458 ls->setCurrentLandscapeID(ls->getDefaultLandscapeID());
459 }
460
461+ // GZ populate site list with sites only from that planet, or full list for Earth (faster than removing the ~50 non-Earth positions...).
462+ StelLocationMgr &locMgr=StelApp::getInstance().getLocationMgr();
463+ QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(this);
464+ if (loc.planetName == "Earth")
465+ {
466+ proxyModel->setSourceModel((QAbstractItemModel*)locMgr.getModelAll());
467+ }
468+ else
469+ {
470+ locMgr.pickLocationsNearby(loc.planetName, 0.0f, 0.0f, 180.0f);
471+ proxyModel->setSourceModel((QAbstractItemModel*)locMgr.getModelPicked());
472+ }
473+ proxyModel->sort(0, Qt::AscendingOrder);
474+ proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
475+ ui->citiesListView->setModel(proxyModel);
476+ ui->citySearchLineEdit->clear();
477+ connect(ui->citySearchLineEdit, SIGNAL(textChanged(const QString&)), proxyModel, SLOT(setFilterWildcard(const QString&)));
478+ ui->citySearchLineEdit->setFocus();
479 }
480 // Planet transition time also set to null to prevent uglyness when
481 // "use landscape location" is enabled for that planet's landscape. --BM
482@@ -429,7 +467,7 @@
483 ui->deleteLocationFromListPushButton->setEnabled(locationMgr.canDeleteUserLocation(loc.getID()));
484 }
485
486-// Called when the user clic on the save button
487+// Called when the user clicks on the save button
488 void LocationDialog::addCurrentLocationToList()
489 {
490 const StelLocation& loc = locationFromFields();
491@@ -456,22 +494,27 @@
492 }
493
494 // Called when the user wants to use the current location as default
495-void LocationDialog::setDefaultLocation()
496+void LocationDialog::setDefaultLocation(bool state)
497 {
498- StelCore* core = StelApp::getInstance().getCore();
499- QString currentLocationId = core->getCurrentLocation().getID();
500- core->setDefaultLocationID(currentLocationId);
501+ if (state)
502+ {
503+ StelCore* core = StelApp::getInstance().getCore();
504+ QString currentLocationId = core->getCurrentLocation().getID();
505+ core->setDefaultLocationID(currentLocationId);
506
507- // Why this code even exists? After the previous code, this should always
508- // be true, except if setting the default location somehow fails. --BM
509- bool isDefault = (currentLocationId == core->getDefaultLocationID());
510- disconnectEditSignals();
511- updateDefaultLocationControls(isDefault);
512- //The focus need to be switched to another control, otherwise
513- //ui->latitudeSpinBox receives it and emits a valueChanged() signal when
514- //the window is closed.
515- ui->citySearchLineEdit->setFocus();
516- connectEditSignals();
517+ // Why this code even exists? After the previous code, this should always
518+ // be true, except if setting the default location somehow fails. --BM
519+ bool isDefault = (currentLocationId == core->getDefaultLocationID());
520+ disconnectEditSignals();
521+ updateDefaultLocationControls(isDefault);
522+ ui->pushButtonReturnToDefault->setEnabled(!isDefault);
523+ ui->useIpQueryCheckBox->setChecked(!state);
524+ //The focus need to be switched to another control, otherwise
525+ //ui->latitudeSpinBox receives it and emits a valueChanged() signal when
526+ //the window is closed.
527+ ui->citySearchLineEdit->setFocus();
528+ connectEditSignals();
529+ }
530 }
531
532 // Called when the user clicks on the delete button
533@@ -484,6 +527,54 @@
534 void LocationDialog::updateDefaultLocationControls(bool currentIsDefault)
535 {
536 ui->useAsDefaultLocationCheckBox->setChecked(currentIsDefault);
537- ui->useAsDefaultLocationCheckBox->setEnabled(!currentIsDefault);
538- ui->pushButtonReturnToDefault->setEnabled(!currentIsDefault);
539+ ui->useAsDefaultLocationCheckBox->setEnabled(!currentIsDefault);
540+}
541+
542+// called when the user clicks on the IP Query button
543+void LocationDialog::ipQueryLocation(bool state)
544+{
545+ if (state)
546+ {
547+ QSettings* conf = StelApp::getInstance().getSettings();
548+ conf->setValue("init_location/location", "auto");
549+ disconnectEditSignals();
550+ resetCompleteList(); // in case we are on Moon/Mars, we must get list back to show all (earth) locations...
551+ StelLocationMgr &locMgr=StelApp::getInstance().getLocationMgr();
552+ locMgr.locationFromIP(); // This just triggers asynchronous lookup.
553+ ui->useAsDefaultLocationCheckBox->setChecked(!state);
554+ ui->pushButtonReturnToDefault->setEnabled(!state);
555+ connectEditSignals();
556+ ui->citySearchLineEdit->setFocus();
557+ }
558+}
559+
560+// called when user clicks "reset list"
561+void LocationDialog::resetCompleteList()
562+{
563+ QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(this);
564+ proxyModel->setSourceModel((QAbstractItemModel*)StelApp::getInstance().getLocationMgr().getModelAll());
565+ proxyModel->sort(0, Qt::AscendingOrder);
566+ proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
567+ ui->citiesListView->setModel(proxyModel);
568+ ui->citySearchLineEdit->clear();
569+ connect(ui->citySearchLineEdit, SIGNAL(textChanged(const QString&)), proxyModel, SLOT(setFilterWildcard(const QString&)));
570+ ui->citySearchLineEdit->setFocus();
571+}
572+
573+// called when user clicks in the country combobox and selects a country. The locations in the list are updated to select only sites in that country.
574+void LocationDialog::filterSitesByCountry()
575+{
576+ QString country=ui->countryNameComboBox->currentData().toString();
577+ QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(this);
578+ StelLocationMgr &locMgr=StelApp::getInstance().getLocationMgr();
579+
580+ locMgr.pickLocationsInCountry(country);
581+ proxyModel->setSourceModel((QAbstractItemModel*)locMgr.getModelPicked());
582+
583+ proxyModel->sort(0, Qt::AscendingOrder);
584+ proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
585+ ui->citiesListView->setModel(proxyModel);
586+ ui->citySearchLineEdit->clear();
587+ connect(ui->citySearchLineEdit, SIGNAL(textChanged(const QString&)), proxyModel, SLOT(setFilterWildcard(const QString&)));
588+ ui->citySearchLineEdit->setFocus();
589 }
590
591=== modified file 'src/gui/LocationDialog.hpp'
592--- src/gui/LocationDialog.hpp 2013-10-14 09:27:54 +0000
593+++ src/gui/LocationDialog.hpp 2014-08-08 12:24:49 +0000
594@@ -82,6 +82,7 @@
595 void updateFromProgram(const StelLocation& location);
596
597 //! Called when the map is clicked.
598+ //! GZ_New: create new list for places nearby and feed into location list box.
599 void setPositionFromMap(double longitude, double latitude);
600
601 //! Called when the user activates an item from the locations list.
602@@ -97,9 +98,18 @@
603
604 //! Called when the user clicks on the delete button
605 void deleteCurrentLocationFromList();
606+
607+ //! filter city list to show entries from single country only
608+ void filterSitesByCountry();
609+
610+ //! reset city list to complete list (may have been reduced to picked list)
611+ void resetCompleteList();
612+
613+ //! called when the user wants get location from network
614+ void ipQueryLocation(bool state);
615
616 //! Called when the user wants to use the current location as default
617- void setDefaultLocation();
618+ void setDefaultLocation(bool state);
619
620 private:
621 QString lastPlanet;
622
623=== modified file 'src/gui/StelGuiItems.cpp'
624--- src/gui/StelGuiItems.cpp 2014-06-09 01:02:28 +0000
625+++ src/gui/StelGuiItems.cpp 2014-08-08 12:24:49 +0000
626@@ -579,9 +579,7 @@
627 }
628 if (flagShowLocation && loc->name.isEmpty())
629 {
630- newLocation = q_(loc->planetName)+", "
631- +StelUtils::radToDmsStr(loc->latitude)+", "
632- +StelUtils::radToDmsStr(loc->longitude);
633+ newLocation = q_(loc->planetName)+", "+StelUtils::decDegToDmsStr(loc->latitude)+", "+StelUtils::decDegToDmsStr(loc->longitude);
634 }
635 if (location->text()!=newLocation)
636 {
637@@ -593,12 +591,18 @@
638 if (lat >= 0)
639 pm = "N";
640 else
641+ {
642 pm = "S";
643+ lat *= -1;
644+ }
645 latStr = QString("%1%2%3").arg(pm).arg(lat).arg(QChar(0x00B0));
646- if (lat >= 0)
647+ if (lon >= 0)
648 pm = "E";
649 else
650+ {
651 pm = "W";
652+ lon *= -1;
653+ }
654 lonStr = QString("%1%2%3").arg(pm).arg(lon).arg(QChar(0x00B0));
655 location->setToolTip(QString("%1 %2").arg(latStr).arg(lonStr));
656 }
657
658=== modified file 'src/gui/locationDialogGui.ui'
659--- src/gui/locationDialogGui.ui 2014-06-16 13:43:31 +0000
660+++ src/gui/locationDialogGui.ui 2014-08-08 12:24:49 +0000
661@@ -7,7 +7,7 @@
662 <x>0</x>
663 <y>0</y>
664 <width>700</width>
665- <height>452</height>
666+ <height>460</height>
667 </rect>
668 </property>
669 <property name="styleSheet">
670@@ -359,6 +359,16 @@
671 </property>
672 </widget>
673 </item>
674+ <item>
675+ <widget class="QPushButton" name="resetListPushButton">
676+ <property name="toolTip">
677+ <string>Reset location list to show all known locations</string>
678+ </property>
679+ <property name="text">
680+ <string>Reset Location List</string>
681+ </property>
682+ </widget>
683+ </item>
684 </layout>
685 </widget>
686 </item>
687@@ -383,113 +393,20 @@
688 <property name="bottomMargin">
689 <number>0</number>
690 </property>
691- <item row="2" column="0" colspan="3">
692- <widget class="QFrame" name="frame_3">
693- <property name="minimumSize">
694+ <item row="1" column="2" colspan="2">
695+ <spacer name="verticalSpacer">
696+ <property name="orientation">
697+ <enum>Qt::Vertical</enum>
698+ </property>
699+ <property name="sizeHint" stdset="0">
700 <size>
701- <width>0</width>
702- <height>0</height>
703+ <width>20</width>
704+ <height>40</height>
705 </size>
706 </property>
707- <property name="frameShape">
708- <enum>QFrame::StyledPanel</enum>
709- </property>
710- <property name="frameShadow">
711- <enum>QFrame::Raised</enum>
712- </property>
713- <layout class="QHBoxLayout" name="horizontalLayout">
714- <property name="leftMargin">
715- <number>0</number>
716- </property>
717- <property name="topMargin">
718- <number>0</number>
719- </property>
720- <property name="rightMargin">
721- <number>0</number>
722- </property>
723- <property name="bottomMargin">
724- <number>0</number>
725- </property>
726- <item>
727- <widget class="QCheckBox" name="useAsDefaultLocationCheckBox">
728- <property name="font">
729- <font>
730- <stylestrategy>PreferDefault</stylestrategy>
731- </font>
732- </property>
733- <property name="focusPolicy">
734- <enum>Qt::NoFocus</enum>
735- </property>
736- <property name="text">
737- <string>Use as default</string>
738- </property>
739- </widget>
740- </item>
741- <item>
742- <widget class="QPushButton" name="pushButtonReturnToDefault">
743- <property name="focusPolicy">
744- <enum>Qt::NoFocus</enum>
745- </property>
746- <property name="text">
747- <string>Return to default</string>
748- </property>
749- </widget>
750- </item>
751- <item>
752- <spacer name="horizontalSpacer">
753- <property name="orientation">
754- <enum>Qt::Horizontal</enum>
755- </property>
756- <property name="sizeHint" stdset="0">
757- <size>
758- <width>40</width>
759- <height>20</height>
760- </size>
761- </property>
762- </spacer>
763- </item>
764- <item>
765- <widget class="QPushButton" name="deleteLocationFromListPushButton">
766- <property name="enabled">
767- <bool>false</bool>
768- </property>
769- <property name="minimumSize">
770- <size>
771- <width>60</width>
772- <height>0</height>
773- </size>
774- </property>
775- <property name="focusPolicy">
776- <enum>Qt::NoFocus</enum>
777- </property>
778- <property name="text">
779- <string>Delete</string>
780- </property>
781- </widget>
782- </item>
783- <item>
784- <widget class="QPushButton" name="addLocationToListPushButton">
785- <property name="enabled">
786- <bool>false</bool>
787- </property>
788- <property name="minimumSize">
789- <size>
790- <width>100</width>
791- <height>0</height>
792- </size>
793- </property>
794- <property name="focusPolicy">
795- <enum>Qt::NoFocus</enum>
796- </property>
797- <property name="text">
798- <string>Add to list</string>
799- </property>
800- </widget>
801- </item>
802- </layout>
803- </widget>
804+ </spacer>
805 </item>
806- <item row="0" column="0">
807+ <item row="0" column="1">
808 <widget class="QFrame" name="frame_4">
809 <property name="minimumSize">
810 <size>
811@@ -603,7 +520,114 @@
812 </layout>
813 </widget>
814 </item>
815+ <item row="2" column="1" colspan="3">
816+ <widget class="QFrame" name="frame_3">
817+ <property name="minimumSize">
818+ <size>
819+ <width>0</width>
820+ <height>0</height>
821+ </size>
822+ </property>
823+ <property name="frameShape">
824+ <enum>QFrame::StyledPanel</enum>
825+ </property>
826+ <property name="frameShadow">
827+ <enum>QFrame::Raised</enum>
828+ </property>
829+ <layout class="QHBoxLayout" name="horizontalLayout">
830+ <property name="leftMargin">
831+ <number>0</number>
832+ </property>
833+ <property name="topMargin">
834+ <number>0</number>
835+ </property>
836+ <property name="rightMargin">
837+ <number>0</number>
838+ </property>
839+ <property name="bottomMargin">
840+ <number>0</number>
841+ </property>
842+ <item>
843+ <spacer name="horizontalSpacer">
844+ <property name="orientation">
845+ <enum>Qt::Horizontal</enum>
846+ </property>
847+ <property name="sizeHint" stdset="0">
848+ <size>
849+ <width>40</width>
850+ <height>20</height>
851+ </size>
852+ </property>
853+ </spacer>
854+ </item>
855+ <item>
856+ <widget class="QPushButton" name="pushButtonReturnToDefault">
857+ <property name="enabled">
858+ <bool>false</bool>
859+ </property>
860+ <property name="focusPolicy">
861+ <enum>Qt::NoFocus</enum>
862+ </property>
863+ <property name="text">
864+ <string>Return to default location</string>
865+ </property>
866+ </widget>
867+ </item>
868+ <item>
869+ <widget class="QPushButton" name="deleteLocationFromListPushButton">
870+ <property name="enabled">
871+ <bool>false</bool>
872+ </property>
873+ <property name="minimumSize">
874+ <size>
875+ <width>60</width>
876+ <height>0</height>
877+ </size>
878+ </property>
879+ <property name="focusPolicy">
880+ <enum>Qt::NoFocus</enum>
881+ </property>
882+ <property name="text">
883+ <string>Delete</string>
884+ </property>
885+ </widget>
886+ </item>
887+ <item>
888+ <widget class="QPushButton" name="addLocationToListPushButton">
889+ <property name="enabled">
890+ <bool>false</bool>
891+ </property>
892+ <property name="minimumSize">
893+ <size>
894+ <width>100</width>
895+ <height>0</height>
896+ </size>
897+ </property>
898+ <property name="focusPolicy">
899+ <enum>Qt::NoFocus</enum>
900+ </property>
901+ <property name="text">
902+ <string>Add to list</string>
903+ </property>
904+ </widget>
905+ </item>
906+ </layout>
907+ </widget>
908+ </item>
909 <item row="0" column="2">
910+ <spacer name="horizontalSpacer_2">
911+ <property name="orientation">
912+ <enum>Qt::Horizontal</enum>
913+ </property>
914+ <property name="sizeHint" stdset="0">
915+ <size>
916+ <width>40</width>
917+ <height>20</height>
918+ </size>
919+ </property>
920+ </spacer>
921+ </item>
922+ <item row="0" column="3">
923 <widget class="QFrame" name="frame_5">
924 <property name="minimumSize">
925 <size>
926@@ -717,31 +741,19 @@
927 </layout>
928 </widget>
929 </item>
930- <item row="1" column="1" colspan="2">
931- <spacer name="verticalSpacer">
932- <property name="orientation">
933- <enum>Qt::Vertical</enum>
934- </property>
935- <property name="sizeHint" stdset="0">
936- <size>
937- <width>20</width>
938- <height>40</height>
939- </size>
940- </property>
941- </spacer>
942+ <item row="3" column="1">
943+ <widget class="QCheckBox" name="useAsDefaultLocationCheckBox">
944+ <property name="text">
945+ <string>Use current location as default</string>
946+ </property>
947+ </widget>
948 </item>
949- <item row="0" column="1">
950- <spacer name="horizontalSpacer_2">
951- <property name="orientation">
952- <enum>Qt::Horizontal</enum>
953- </property>
954- <property name="sizeHint" stdset="0">
955- <size>
956- <width>40</width>
957- <height>20</height>
958- </size>
959- </property>
960- </spacer>
961+ <item row="3" column="3">
962+ <widget class="QCheckBox" name="useIpQueryCheckBox">
963+ <property name="text">
964+ <string>Get location from Network</string>
965+ </property>
966+ </widget>
967 </item>
968 </layout>
969 </widget>
970
971=== modified file 'src/tests/testConversions.cpp'
972--- src/tests/testConversions.cpp 2014-06-06 18:02:00 +0000
973+++ src/tests/testConversions.cpp 2014-08-08 12:24:49 +0000
974@@ -171,3 +171,44 @@
975 QVERIFY2(std::abs(angle1-angle2)<=ERROR_LIMIT, qPrintable(QString("%1rad=%2%3d%4m%5s").arg(rad).arg(s).arg(dego).arg(mino).arg(seco)));
976 }
977 }
978+
979+void TestConversions::testDDToDMS()
980+{
981+ QVariantList data;
982+
983+ data << 0. << 0 << 0 << 0.;
984+ data << 10. << 10 << 0 << 0.;
985+ data << -13.5 << -13 << 30 << 0.;
986+ data << 30.263888889 << 30 << 15 << 50.;
987+ data << -90.1 << -90 << 6 << 0.;
988+ data << 128.9999 << 128 << 59 << 59.64;
989+ data << 360.6 << 360 << 36 << 0.;
990+ data << -180.786 << -180 << 47 << 9.6;
991+ data << -0.01 << -0 << 0 << 36.;
992+ data << -0.039 << -0 << 2 << 20.4;
993+
994+ while (data.count()>=4)
995+ {
996+ double angle, sec, seco, angle1, angle2;
997+ int deg, min;
998+ unsigned int dego, mino;
999+ bool sign;
1000+ QString s = "+";
1001+ angle = data.takeFirst().toDouble();
1002+ deg = data.takeFirst().toInt();
1003+ min = data.takeFirst().toInt();
1004+ sec = data.takeFirst().toDouble();
1005+ if (angle>=0)
1006+ angle1 = sec+min*60+deg*3600;
1007+ else
1008+ angle1 = -1*(sec+min*60+std::abs((double)deg)*3600);
1009+ StelUtils::decDegToDms(angle, sign, dego, mino, seco);
1010+ angle2 = seco+mino*60+dego*3600;
1011+ if (!sign)
1012+ {
1013+ angle2 *= -1;
1014+ s = "-";
1015+ }
1016+ QVERIFY2(std::abs(angle1-angle2)<=ERROR_LIMIT, qPrintable(QString("%1degrees=%2%3d%4m%5s").arg(angle).arg(s).arg(dego).arg(mino).arg(seco)));
1017+ }
1018+}
1019
1020=== modified file 'src/tests/testConversions.hpp'
1021--- src/tests/testConversions.hpp 2014-06-07 11:39:09 +0000
1022+++ src/tests/testConversions.hpp 2014-08-08 12:24:49 +0000
1023@@ -31,6 +31,7 @@
1024 void testDMSToRad();
1025 void testRadToHMS();
1026 void testRadToDMS();
1027+ void testDDToDMS();
1028 };
1029
1030 #endif // _TESTCONVERSIONS_HPP_