Merge lp:~registry/stellarium/socis2015 into lp:stellarium

Proposed by Alexander Wolf
Status: Merged
Merged at revision: 8441
Proposed branch: lp:~registry/stellarium/socis2015
Merge into: lp:stellarium
Diff against target: 72667 lines (+65875/-1760)
236 files modified
CMakeLists.txt (+28/-9)
cmake/Doxyfile.cmake (+8/-5)
data/CMakeLists.txt (+5/-2)
data/gui/normalStyle.css (+1/-1)
doc/DoxygenLayout.xml (+1/-1)
doc/doxygen.css (+2/-1)
doc/mainpage.doxygen (+3/-3)
doc/plugIns.doxygen (+1/-0)
guide/plg_interfaces.tex (+95/-1)
plugins/ArchaeoLines/src/ArchaeoLines.cpp (+27/-10)
plugins/ArchaeoLines/src/ArchaeoLines.hpp (+23/-14)
plugins/ArchaeoLines/src/gui/ArchaeoLinesDialog.cpp (+8/-1)
plugins/ArchaeoLines/src/gui/ArchaeoLinesDialog.hpp (+1/-0)
plugins/Oculars/src/Oculars.cpp (+57/-82)
plugins/Oculars/src/Oculars.hpp (+15/-1)
plugins/Oculars/src/gui/OcularsGuiPanel.cpp (+115/-132)
plugins/RemoteControl/CMakeLists.txt (+46/-0)
plugins/RemoteControl/COPYING (+340/-0)
plugins/RemoteControl/RemoteControl.qrc (+6/-0)
plugins/RemoteControl/doc/qtwebapp.doxygen (+35/-0)
plugins/RemoteControl/doc/remoteControl.doxygen (+61/-0)
plugins/RemoteControl/doc/remoteControlApi.doxygen (+461/-0)
plugins/RemoteControl/doc/remoteControlWeb.doxygen (+564/-0)
plugins/RemoteControl/src/APIController.cpp (+141/-0)
plugins/RemoteControl/src/APIController.hpp (+64/-0)
plugins/RemoteControl/src/AbstractAPIService.cpp (+159/-0)
plugins/RemoteControl/src/AbstractAPIService.hpp (+160/-0)
plugins/RemoteControl/src/CMakeLists.txt (+78/-0)
plugins/RemoteControl/src/LocationSearchService.cpp (+104/-0)
plugins/RemoteControl/src/LocationSearchService.hpp (+58/-0)
plugins/RemoteControl/src/LocationService.cpp (+258/-0)
plugins/RemoteControl/src/LocationService.hpp (+56/-0)
plugins/RemoteControl/src/MainService.cpp (+622/-0)
plugins/RemoteControl/src/MainService.hpp (+122/-0)
plugins/RemoteControl/src/ObjectService.cpp (+216/-0)
plugins/RemoteControl/src/ObjectService.hpp (+67/-0)
plugins/RemoteControl/src/RemoteControl.cpp (+288/-0)
plugins/RemoteControl/src/RemoteControl.hpp (+179/-0)
plugins/RemoteControl/src/RequestHandler.cpp (+222/-0)
plugins/RemoteControl/src/RequestHandler.hpp (+88/-0)
plugins/RemoteControl/src/ScriptService.cpp (+169/-0)
plugins/RemoteControl/src/ScriptService.hpp (+52/-0)
plugins/RemoteControl/src/SimbadService.cpp (+193/-0)
plugins/RemoteControl/src/SimbadService.hpp (+53/-0)
plugins/RemoteControl/src/StelActionService.cpp (+115/-0)
plugins/RemoteControl/src/StelActionService.hpp (+54/-0)
plugins/RemoteControl/src/StelPropertyService.cpp (+113/-0)
plugins/RemoteControl/src/StelPropertyService.hpp (+50/-0)
plugins/RemoteControl/src/ViewService.cpp (+201/-0)
plugins/RemoteControl/src/ViewService.hpp (+51/-0)
plugins/RemoteControl/src/gui/RemoteControlDialog.cpp (+182/-0)
plugins/RemoteControl/src/gui/RemoteControlDialog.hpp (+61/-0)
plugins/RemoteControl/src/gui/remoteControlDialog.ui (+323/-0)
plugins/RemoteControl/src/qtwebapp/copyright.txt (+11/-0)
plugins/RemoteControl/src/qtwebapp/httpserver/httpconnectionhandler.cpp (+295/-0)
plugins/RemoteControl/src/qtwebapp/httpserver/httpconnectionhandler.h (+146/-0)
plugins/RemoteControl/src/qtwebapp/httpserver/httpconnectionhandlerpool.cpp (+137/-0)
plugins/RemoteControl/src/qtwebapp/httpserver/httpconnectionhandlerpool.h (+119/-0)
plugins/RemoteControl/src/qtwebapp/httpserver/httpcookie.cpp (+243/-0)
plugins/RemoteControl/src/qtwebapp/httpserver/httpcookie.h (+112/-0)
plugins/RemoteControl/src/qtwebapp/httpserver/httpglobal.cpp (+7/-0)
plugins/RemoteControl/src/qtwebapp/httpserver/httpglobal.h (+30/-0)
plugins/RemoteControl/src/qtwebapp/httpserver/httplistener.cpp (+90/-0)
plugins/RemoteControl/src/qtwebapp/httpserver/httplistener.h (+113/-0)
plugins/RemoteControl/src/qtwebapp/httpserver/httprequest.cpp (+553/-0)
plugins/RemoteControl/src/qtwebapp/httpserver/httprequest.h (+235/-0)
plugins/RemoteControl/src/qtwebapp/httpserver/httprequesthandler.cpp (+21/-0)
plugins/RemoteControl/src/qtwebapp/httpserver/httprequesthandler.h (+50/-0)
plugins/RemoteControl/src/qtwebapp/httpserver/httpresponse.cpp (+202/-0)
plugins/RemoteControl/src/qtwebapp/httpserver/httpresponse.h (+163/-0)
plugins/RemoteControl/src/qtwebapp/httpserver/staticfilecontroller.cpp (+185/-0)
plugins/RemoteControl/src/qtwebapp/httpserver/staticfilecontroller.h (+117/-0)
plugins/RemoteControl/src/qtwebapp/lgpl-3.0.txt (+165/-0)
plugins/RemoteControl/src/qtwebapp/readme.txt (+7/-0)
plugins/RemoteControl/src/qtwebapp/templateengine/template.cpp (+295/-0)
plugins/RemoteControl/src/qtwebapp/templateengine/template.h (+187/-0)
plugins/RemoteControl/src/qtwebapp/templateengine/templateglobal.h (+24/-0)
plugins/RemoteControl/util/update_translationdata.py (+42/-0)
plugins/RemoteControl/webroot/dejavusans-webfont.svg (+6922/-0)
plugins/RemoteControl/webroot/dejavusansmono-webfont.svg (+3318/-0)
plugins/RemoteControl/webroot/external/jquery-ui.css (+1225/-0)
plugins/RemoteControl/webroot/iframestyle.css (+54/-0)
plugins/RemoteControl/webroot/index.html (+496/-0)
plugins/RemoteControl/webroot/js/api/actions.js (+142/-0)
plugins/RemoteControl/webroot/js/api/flags.js (+54/-0)
plugins/RemoteControl/webroot/js/api/location.js (+172/-0)
plugins/RemoteControl/webroot/js/api/properties.js (+161/-0)
plugins/RemoteControl/webroot/js/api/remotecontrol.js (+205/-0)
plugins/RemoteControl/webroot/js/api/scripts.js (+63/-0)
plugins/RemoteControl/webroot/js/api/search.js (+174/-0)
plugins/RemoteControl/webroot/js/api/time.js (+377/-0)
plugins/RemoteControl/webroot/js/api/trunc.js (+8/-0)
plugins/RemoteControl/webroot/js/api/updatequeue.js (+40/-0)
plugins/RemoteControl/webroot/js/api/viewcontrol.js (+131/-0)
plugins/RemoteControl/webroot/js/api/viewoptions.js (+85/-0)
plugins/RemoteControl/webroot/js/globalize.js (+1586/-0)
plugins/RemoteControl/webroot/js/jquery-1.11.3.js (+10351/-0)
plugins/RemoteControl/webroot/js/jquery-ui.js (+16617/-0)
plugins/RemoteControl/webroot/js/jquery.ui.touch-punch.js (+180/-0)
plugins/RemoteControl/webroot/js/main.js (+31/-0)
plugins/RemoteControl/webroot/js/plugins/archaeolines.js (+7/-0)
plugins/RemoteControl/webroot/js/require.js (+2103/-0)
plugins/RemoteControl/webroot/js/settings.js (+22/-0)
plugins/RemoteControl/webroot/js/translationdata.js (+33/-0)
plugins/RemoteControl/webroot/js/ui/actions.js (+84/-0)
plugins/RemoteControl/webroot/js/ui/combobox.js (+148/-0)
plugins/RemoteControl/webroot/js/ui/jqueryuifixes.js (+162/-0)
plugins/RemoteControl/webroot/js/ui/location.js (+237/-0)
plugins/RemoteControl/webroot/js/ui/mainui.js (+334/-0)
plugins/RemoteControl/webroot/js/ui/scripts.js (+90/-0)
plugins/RemoteControl/webroot/js/ui/search.js (+267/-0)
plugins/RemoteControl/webroot/js/ui/time.js (+223/-0)
plugins/RemoteControl/webroot/js/ui/viewcontrol.js (+88/-0)
plugins/RemoteControl/webroot/js/ui/viewoptions.js (+132/-0)
plugins/RemoteControl/webroot/style.css (+889/-0)
plugins/RemoteControl/webroot/style_tablet7in.css (+161/-0)
plugins/RemoteControl/webroot/tablet7in.html (+690/-0)
plugins/RemoteControl/webroot/translate_files (+17/-0)
plugins/RemoteSync/CMakeLists.txt (+20/-0)
plugins/RemoteSync/RemoteSync.qrc (+6/-0)
plugins/RemoteSync/src/CMakeLists.txt (+43/-0)
plugins/RemoteSync/src/RemoteSync.cpp (+276/-0)
plugins/RemoteSync/src/RemoteSync.hpp (+159/-0)
plugins/RemoteSync/src/SyncClient.cpp (+185/-0)
plugins/RemoteSync/src/SyncClient.hpp (+71/-0)
plugins/RemoteSync/src/SyncClientHandlers.cpp (+243/-0)
plugins/RemoteSync/src/SyncClientHandlers.hpp (+89/-0)
plugins/RemoteSync/src/SyncMessages.cpp (+171/-0)
plugins/RemoteSync/src/SyncMessages.hpp (+127/-0)
plugins/RemoteSync/src/SyncProtocol.cpp (+227/-0)
plugins/RemoteSync/src/SyncProtocol.hpp (+191/-0)
plugins/RemoteSync/src/SyncServer.cpp (+294/-0)
plugins/RemoteSync/src/SyncServer.hpp (+86/-0)
plugins/RemoteSync/src/SyncServerEventSenders.cpp (+104/-0)
plugins/RemoteSync/src/SyncServerEventSenders.hpp (+131/-0)
plugins/RemoteSync/src/SyncServerHandlers.cpp (+105/-0)
plugins/RemoteSync/src/SyncServerHandlers.hpp (+61/-0)
plugins/RemoteSync/src/gui/RemoteSyncDialog.cpp (+207/-0)
plugins/RemoteSync/src/gui/RemoteSyncDialog.hpp (+60/-0)
plugins/RemoteSync/src/gui/remoteSyncDialog.ui (+373/-0)
plugins/Scenery3d/src/Scenery3d.cpp (+4/-2)
plugins/TextUserInterface/src/TextUserInterface.cpp (+6/-14)
plugins/TextUserInterface/src/TextUserInterface.hpp (+0/-1)
po/CMakeLists.txt (+3/-0)
po/stellarium-remotecontrol/CMakeLists.txt (+73/-0)
po/stellarium-remotecontrol/POTFILES.in (+23/-0)
po/stellarium-remotecontrol/en.po (+325/-0)
po/stellarium-remotecontrol/stellarium-remotecontrol-js.pot (+128/-0)
po/stellarium-remotecontrol/stellarium-remotecontrol.pot (+600/-0)
scripts/tests/real_time.ssc (+2/-2)
src/CLIProcessor.cpp (+6/-1)
src/CMakeLists.txt (+19/-0)
src/StelLogger.cpp (+11/-0)
src/StelLogger.hpp (+2/-0)
src/StelMainView.cpp (+23/-5)
src/core/SimbadSearcher.cpp (+20/-2)
src/core/SimbadSearcher.hpp (+4/-1)
src/core/StelActionMgr.cpp (+64/-54)
src/core/StelActionMgr.hpp (+84/-37)
src/core/StelApp.cpp (+19/-12)
src/core/StelApp.hpp (+7/-4)
src/core/StelAudioMgr.cpp (+52/-0)
src/core/StelAudioMgr.hpp (+12/-0)
src/core/StelCore.cpp (+108/-7)
src/core/StelCore.hpp (+58/-10)
src/core/StelLocation.cpp (+6/-0)
src/core/StelLocation.hpp (+7/-0)
src/core/StelLocationMgr.cpp (+34/-26)
src/core/StelLocationMgr.hpp (+28/-29)
src/core/StelModule.cpp (+6/-1)
src/core/StelModule.hpp (+16/-3)
src/core/StelModuleMgr.cpp (+4/-0)
src/core/StelMovementMgr.cpp (+150/-33)
src/core/StelMovementMgr.hpp (+74/-18)
src/core/StelObject.cpp (+3/-1)
src/core/StelObject.hpp (+8/-3)
src/core/StelObjectModule.hpp (+1/-0)
src/core/StelObjectType.hpp (+2/-0)
src/core/StelObserver.cpp (+5/-3)
src/core/StelObserver.hpp (+9/-1)
src/core/StelProjector.cpp (+1/-0)
src/core/StelProjector.hpp (+6/-3)
src/core/StelProjectorClasses.cpp (+28/-17)
src/core/StelPropertyMgr.cpp (+225/-0)
src/core/StelPropertyMgr.hpp (+318/-0)
src/core/StelRegionObject.hpp (+8/-6)
src/core/StelSkyCultureMgr.cpp (+44/-1)
src/core/StelSkyCultureMgr.hpp (+20/-1)
src/core/StelSkyDrawer.cpp (+25/-20)
src/core/StelSkyDrawer.hpp (+83/-27)
src/core/StelTranslator.cpp (+5/-0)
src/core/StelTranslator.hpp (+8/-0)
src/core/StelUtils.cpp (+15/-5)
src/core/StelUtils.hpp (+2/-2)
src/core/VecMath.hpp (+16/-0)
src/core/modules/Constellation.cpp (+3/-2)
src/core/modules/Constellation.hpp (+3/-0)
src/core/modules/ConstellationMgr.cpp (+66/-25)
src/core/modules/ConstellationMgr.hpp (+43/-13)
src/core/modules/LabelMgr.cpp (+4/-1)
src/core/modules/LandscapeMgr.cpp (+50/-18)
src/core/modules/LandscapeMgr.hpp (+80/-15)
src/core/modules/MilkyWay.cpp (+1/-1)
src/core/modules/MilkyWay.hpp (+8/-2)
src/core/modules/Nebula.hpp (+9/-8)
src/core/modules/NebulaMgr.cpp (+31/-16)
src/core/modules/NebulaMgr.hpp (+58/-14)
src/core/modules/SolarSystem.cpp (+34/-10)
src/core/modules/SolarSystem.hpp (+55/-6)
src/core/modules/SporadicMeteorMgr.cpp (+5/-2)
src/core/modules/StarMgr.cpp (+1/-1)
src/core/modules/StarMgr.hpp (+10/-5)
src/core/modules/ZodiacalLight.cpp (+1/-0)
src/core/modules/ZodiacalLight.hpp (+126/-120)
src/gui/AtmosphereDialog.cpp (+3/-10)
src/gui/ConfigurationDialog.cpp (+12/-27)
src/gui/LocationDialog.cpp (+25/-40)
src/gui/LocationDialog.hpp (+9/-0)
src/gui/ScriptConsole.cpp (+24/-60)
src/gui/ScriptConsole.hpp (+2/-0)
src/gui/SearchDialog.cpp (+8/-34)
src/gui/SearchDialog.hpp (+49/-6)
src/gui/StelDialog.cpp (+405/-220)
src/gui/StelDialog.hpp (+56/-5)
src/gui/StelDialog_p.hpp (+110/-0)
src/gui/StelGuiItems.hpp (+10/-3)
src/gui/ViewDialog.cpp (+242/-388)
src/gui/ViewDialog.hpp (+15/-18)
src/gui/configurationDialog.ui (+5/-1)
src/gui/viewDialog.ui (+6/-3)
src/scripting/ScreenImageMgr.cpp (+8/-6)
src/scripting/ScreenImageMgr.hpp (+5/-2)
src/scripting/StelMainScriptAPI.cpp (+36/-13)
src/scripting/StelMainScriptAPI.hpp (+37/-4)
src/scripting/StelScriptMgr.cpp (+95/-26)
src/scripting/StelScriptMgr.hpp (+56/-20)
To merge this branch: bzr merge lp:~registry/stellarium/socis2015
Reviewer Review Type Date Requested Status
Fabien Chéreau Approve
gzotti Approve
Review via email: mp+296492@code.launchpad.net

This proposal supersedes a proposal from 2016-05-11.

Commit message

Merging SoCiS2015 branch: StelProperty system, RemoteControl and preliminary RemoteSync plugin.

Description of the change

This branch introduces a new way how objects distribute changes in their properties: the StelProperty system. (Based on a proper use of the QT_PROPERTY mechanism.) This allows better interaction between several ways to switch settings, not only triggering (via StelAction) but also distributing other data.

The reason for this is its second contribution: RemoteControl plugin. A web interface which allows a presenter in front of a screen to switch almost all things from a handheld tablet (or other computer) with a decent web browser (via JavaScript). Or just start a script via wget or curl per cronjob. The StelProperty system is used to automatically propagate changes into all connected GUIs. This system has now worked flawlessly for several weeks in a big museum installation.

Yet another plugin, RemoteSync, has not been completed so far. I still propose merging this branch now, because StelProperty is working well and should be used in future development, and also RemoteControl is working well and ready for a first release with V0.15.0. Both plugins will become better over time. For now, I recommend deactivating RemoteSync from default builds, it does not otherwise disturb.

To post a comment you must log in.
Revision history for this message
Fabien Chéreau (xalioth) wrote : Posted in a previous version of this proposal

Hi Florian, Georg,

thanks, that's huge amount of work that you did! I haven't checked the code in a (too) long time, so it took me time to sort out your changes from the ones of the trunk!
General comment: the code is very clean and very well documented, thanks! That's really professional work :)

Comments on the StelProperty:
 - I understand the need for StelProperty/StelPropertyMgr for scripting and more generally GUI/remote controller etc... it is definitely something missing from the current trunk
 - I am not quite sure about creating a new StelProperty class though, as it doesn't seem brings much more than the regular Qt property. If you would adopt the convention used in QtScript of designing a property by the qobjectname.propertyname you may more or less be able to avoid it I think. The property manager would then simply manage the collection of QObject containing the properties to expose and you could use a more standard approach, which will match the scripting language API. There is somehow a merge to do with the existing scripting API.
 - Also I'm a bit concerned with the partial duplication of features with StelAction, or at least the additional complexity to grasp the difference and when to use which. Did you consider forcing StelAction to use a StelProperty/QProperty and remove the other kind of binding to functions? I think it would make sense.

On the RemoteControl plugin:
 - it would be good to move all related data inside the plugin folder instead of keeping them in data/ (i.e. move data/webroot stuff in the plguing/RemoteControl/ folder)
 - did you double check all third parties libraries licenses?
 - this plugin should also not be activated by default for security reasons (I didn't check if it's the case)

review: Needs Fixing
Revision history for this message
Florian Schaukowitsch (fschauk) wrote : Posted in a previous version of this proposal
Download full text (3.5 KiB)

Hello Fabien,
thanks for the kind words!

To adress your issues:
StelProperty:
 - Directly using the modules is an interesting idea. This would still retain the StelPropertyMgr as the central access point, having readProperty(QString id) and writeProperty(QString id,QVariant value) methods, and something like connectToPropertyChanged(QString id, QObject* target, QString slot) or similar? A disadvantage would probably be that some string manipulation and lookup must be used each time, for finding out the object name and property name, but we can probably avoid most of this by putting all QMetaProperties of an object in a global QMap when it is registered -- assuming object names never change. Still, in a class using this, the property ID would need to be specified each time, instead of using a single StelProperty reference.
 There could be a method that registers arbitrary QObjects, but maybe we could register all StelModule subclasses automatically. Maybe there are some properties that you do not want exposed, what to do about those? Nevertheless, this system seems to be worth testing out. I probably can retain the other added API as-is (StelDialog, RemoteControl).

 - My consideration was that a StelAction is mainly a wrapper for an UI operation, which can be assigned hotkeys, etc. This only seems to make sense for boolean or argument-less actions, assigning an hotkey to an Q_PROPERTY of arbitrary type would be a bit strange? StelProperty on the other hand is more of an development/power-user tool to directly access internals of the various classes, and reacting to changes of these properties if desired. Actually, I have modified StelAction to use a StelProperty when possible, meaning when bound to a boolean Q_PROPERTY with a NOTIFY event, it internally creates and uses a StelProperty with the same name as the action. I still think that it makes sense to retain at least the direct connection to an argumentless slot somehow, to enable actions that have no inherent "state". I found the variant with a slot(bool) to be a bit weird because the StelAction has to track the current "state" itself, which could possibly lead to discrepencies if the slot is called directly elsewhere. Nevertheless, I think this variant is not really used that much, and introducing a boolean property for these cases should not be hard.

RemoteControl:
 - In the source tree, the webroot folder could be easily moved to the plugin folder. Do you still want to move it to 'share/${PACKAGE}/data/webroot' for the installation, or is there a better folder? I think there is no "modules" folder in the installation directory, or is there? The web server does not use StelFileMgr internally (for performance/consistency reasons), therefore I think adding an webroot override path to the configuration file, so that users can replace the interface without it being overridden by app updates, should also work. Or should a webroot folder in '~/.stellarium/data' (or maybe '~/.stellarium/modules/RemoteControl/webroot') automatically be used?

 - The only new library used is Stefan Fring's QtWebApp (http://stefanfrings.de/qtwebapp/index-en.html), which is licensed under the LGPL (no version...

Read more...

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

Hi,

see me replies inline

On Thu, May 19, 2016 at 12:31 AM, Florian Schaukowitsch <
<email address hidden>> wrote:

> Hello Fabien,
> thanks for the kind words!
>
> To adress your issues:
> StelProperty:
> - Directly using the modules is an interesting idea. This would still
> retain the StelPropertyMgr as the central access point, having
> readProperty(QString id) and writeProperty(QString id,QVariant value)
> methods, and something like connectToPropertyChanged(QString id, QObject*
> target, QString slot) or similar? A disadvantage would probably be that
> some string manipulation and lookup must be used each time, for finding out
> the object name and property name, but we can probably avoid most of this
> by putting all QMetaProperties of an object in a global QMap when it is
> registered -- assuming object names never change. Still, in a class using
> this, the property ID would need to be specified each time, instead of
> using a single StelProperty reference.
>

Yes there are drawbacks, but somehow this was already done for
QtScript/QML, which allow access to QObjects by names.

> There could be a method that registers arbitrary QObjects, but maybe we
> could register all StelModule subclasses automatically. Maybe there are
> some properties that you do not want exposed, what to do about those?

We should check if there are. But we could also probably just assume that
the preliminary goal of using Qproperties on a value is precisely to expose
it to script/GUI/remote control

> Nevertheless, this system seems to be worth testing out. I probably can
> retain the other added API as-is (StelDialog, RemoteControl).
>

yes, excepted a properties renaming, this should not be different from the
point of view of the external user of the API

> - My consideration was that a StelAction is mainly a wrapper for an UI
> operation, which can be assigned hotkeys, etc. This only seems to make
> sense for boolean or argument-less actions, assigning an hotkey to an
> Q_PROPERTY of arbitrary type would be a bit strange? StelProperty on the
> other hand is more of an development/power-user tool to directly access
> internals of the various classes, and reacting to changes of these
> properties if desired. Actually, I have modified StelAction to use a
> StelProperty when possible, meaning when bound to a boolean Q_PROPERTY with
> a NOTIFY event, it internally creates and uses a StelProperty with the same
> name as the action. I still think that it makes sense to retain at least
> the direct connection to an argumentless slot somehow, to enable actions
> that have no inherent "state". I found the variant with a slot(bool) to be
> a bit weird because the StelAction has to track the current "state" itself,
> which could possibly lead to discrepencies if the slot is called directly
> elsewhere. Nevertheless, I think this variant is not really used that much,
> and introducing a boolean property for these cases should not be hard.
>

OK, I didn't look in enough details to conclude on that so please do as you
think is the best. Just try to refactor and simplify other parts of the
code if possible, even if you remove not much used feat...

Read more...

Revision history for this message
Florian Schaukowitsch (fschauk) wrote : Posted in a previous version of this proposal

Sorry for the delay, I was sick for a few days and then I somehow managed to mess up my Qt installation so hard that even a reinstall could not fix it :P

I tried out a few things. The StelPropertyMgr can now register arbitrary QObjects and their properties. All StelModules are automatically registered (in StelModuleMgr::registerModule), also the StelSkyCultureMgr, StelSkyDrawer and StelCore are manually registered for now.

The properties can now be accessed with a "<objectName>.<propertyName>" ID, like in QtScript. The properties are put into a QMap when registered, no dynamic lookup/string manipulation is done (meaning the QObject name of an object should stay the same during runtime, but it does for all our classes). The StelProperty class itself is still retained, I think this is the best coding style and has less overhead than the alternatives. Normaly, you don't even need to use the class itself, if you are a StelModule developer you now don't have to do *anything special at all* to provide access to your properties through the StelProperty system. The connectIntProperty/connectDoubleProperty... methods in StelDialog hide all the complexity for GUI connections.

I removed the support for bool slots from StelAction, the Oculars plugin seems to be the only place this was used. StelAction now has basically 2 modes:
- connection to a bool Q_PROPERTY - the property is also registered as StelProperty with the ID of the action, a NOTIFY signal is recommended but not required
- connection to an argumentless slot, which I still think is a valid use-case
I don't think we should split this up further or combine it with StelProperty somehow because of the different uses these classes should have.

I am quite happy now with the current system, what do you think?

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

Looks very good IMHO, thank you!
Fabien?

review: Needs Resubmitting
lp:~registry/stellarium/socis2015 updated
7781. By Alexander Wolf

A small fix for translations support

7782. By Alexander Wolf

A small fix for cmake

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

Well, I resubmitted the Merge, so what else can I say? A small merge conflict should be cleaned up during the merge.

review: Approve
lp:~registry/stellarium/socis2015 updated
7783. By gzotti

removed useless files

7784. By Alexander Wolf

sync with trunk; avoid conflicts

7785. By Alexander Wolf

added changes for Miller projection

Revision history for this message
Fabien Chéreau (xalioth) wrote :

Hi Florian, thanks! I think we can merge now, sorry for the slow reaction..

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2016-06-05 07:56:01 +0000
3+++ CMakeLists.txt 2016-06-12 13:59:22 +0000
4@@ -18,9 +18,15 @@
5
6 ########### Project name ###########
7 PROJECT(Stellarium)
8-SET(STELLARIUM_MAJOR "0")
9-SET(STELLARIUM_MINOR "14")
10-SET(STELLARIUM_PATCH "90")
11+# Use integer versions instead of strings for easier handling if required
12+SET(STELLARIUM_MAJOR 0)
13+SET(STELLARIUM_MINOR 14)
14+SET(STELLARIUM_PATCH 90)
15+ADD_DEFINITIONS(
16+-DSTELLARIUM_MAJOR=${STELLARIUM_MAJOR}
17+-DSTELLARIUM_MINOR=${STELLARIUM_MINOR}
18+-DSTELLARIUM_PATCH=${STELLARIUM_PATCH}
19+)
20 SET(VERSION "${STELLARIUM_MAJOR}.${STELLARIUM_MINOR}.${STELLARIUM_PATCH}")
21 SET(PACKAGE stellarium)
22 SET(COPYRIGHT_YEARS "2000-2016")
23@@ -174,7 +180,7 @@
24 SET(STELLARIUM_PLUGINS) # Global list of all the plugins.
25 MACRO(ADD_PLUGIN NAME DEFAULT)
26 STRING(TOUPPER ${NAME} NAME_UP)
27- SET(USE_PLUGIN_${NAME_UP} ${DEFAULT} CACHE BOOL "Define wheter the ${NAME} plugin should be created.")
28+ SET(USE_PLUGIN_${NAME_UP} ${DEFAULT} CACHE BOOL "Define whether the ${NAME} plugin should be created.")
29 SET(STELLARIUM_PLUGINS ${STELLARIUM_PLUGINS} ${NAME})
30 ENDMACRO()
31
32@@ -197,6 +203,9 @@
33 ADD_PLUGIN(PointerCoordinates 1)
34 ADD_PLUGIN(Pulsars 1)
35 ADD_PLUGIN(Quasars 1)
36+# SOCIS 2015:
37+ADD_PLUGIN(RemoteControl 1)
38+ADD_PLUGIN(RemoteSync 0)
39 ADD_PLUGIN(Satellites 1)
40 ADD_PLUGIN(Scenery3d 1)
41 ADD_PLUGIN(SolarSystemEditor 1)
42@@ -461,9 +470,9 @@
43 SET(CPACK_PACKAGE_VENDOR "Stellarium's team")
44 SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README")
45 SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING")
46- SET(CPACK_PACKAGE_VERSION_MAJOR ${STELLARIUM_MAJOR})
47- SET(CPACK_PACKAGE_VERSION_MINOR ${STELLARIUM_MINOR})
48- SET(CPACK_PACKAGE_VERSION_PATCH ${STELLARIUM_PATCH})
49+ SET(CPACK_PACKAGE_VERSION_MAJOR "${STELLARIUM_MAJOR}")
50+ SET(CPACK_PACKAGE_VERSION_MINOR "${STELLARIUM_MINOR}")
51+ SET(CPACK_PACKAGE_VERSION_PATCH "${STELLARIUM_PATCH}")
52 SET(CPACK_PACKAGE_INSTALL_DIRECTORY "stellarium")
53 SET(CPACK_SOURCE_PACKAGE_FILE_NAME "stellarium-${VERSION}")
54 SET(CPACK_SOURCE_GENERATOR "TGZ")
55@@ -517,8 +526,18 @@
56 ENDIF()
57
58 ########### Generate doxygen doc ###############
59-CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/cmake/Doxyfile.cmake ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
60-ADD_CUSTOM_TARGET(apidoc doxygen ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Generate the doxygen documentation into the doc directory.")
61+FIND_PACKAGE(Doxygen)
62+IF(DOXYGEN_FOUND)
63+ IF(DOXYGEN_DOT_FOUND)
64+ SET(HAVE_DOT "YES")
65+ SET(DOT_PATH ${DOXYGEN_DOT_PATH})
66+ ELSE()
67+ SET(HAVE_DOT "NO")
68+ SET(DOT_PATH "")
69+ ENDIF()
70+ CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/cmake/Doxyfile.cmake ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
71+ ADD_CUSTOM_TARGET(apidoc ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Generate the doxygen documentation into the doc directory.")
72+ENDIF()
73
74 ##################### Generate translation copying script ######################
75 IF(WIN32)
76
77=== modified file 'cmake/Doxyfile.cmake'
78--- cmake/Doxyfile.cmake 2016-04-21 07:15:21 +0000
79+++ cmake/Doxyfile.cmake 2016-06-12 13:59:22 +0000
80@@ -150,7 +150,7 @@
81 # shortest path that makes the file name unique will be used
82 # The default value is: YES.
83
84-FULL_PATH_NAMES = NO
85+FULL_PATH_NAMES = YES
86
87 # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
88 # Stripping is only done if one of the specified strings matches the left-hand
89@@ -2026,6 +2026,9 @@
90 # run, you must also specify the path to the tagfile here.
91
92 TAGFILES = qt.tag=http://doc.qt.io/qt-5/
93+ qtcore.tags=http://doc.qt.io/qt-5/ \
94+ qtgui.tags=http://doc.qt.io/qt-5/ \
95+ qtwidgets.tags=http://doc.qt.io/qt-5/
96
97 # When a file name is specified after GENERATE_TAGFILE, doxygen will create a
98 # tag file that is based on the input files it reads. See section "Linking to
99@@ -2101,7 +2104,7 @@
100 # set to NO
101 # The default value is: YES.
102
103-HAVE_DOT = NO
104+HAVE_DOT = @HAVE_DOT@
105
106 # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
107 # to run in parallel. When set to 0 doxygen will base this on the number of
108@@ -2143,7 +2146,7 @@
109 # The default value is: YES.
110 # This tag requires that the tag HAVE_DOT is set to YES.
111
112-CLASS_GRAPH = NO
113+CLASS_GRAPH = YES
114
115 # If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
116 # graph for each documented class showing the direct and indirect implementation
117@@ -2152,7 +2155,7 @@
118 # The default value is: YES.
119 # This tag requires that the tag HAVE_DOT is set to YES.
120
121-COLLABORATION_GRAPH = NO
122+COLLABORATION_GRAPH = YES
123
124 # If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
125 # groups, showing the direct groups dependencies.
126@@ -2275,7 +2278,7 @@
127 # found. If left blank, it is assumed the dot tool can be found in the path.
128 # This tag requires that the tag HAVE_DOT is set to YES.
129
130-DOT_PATH =
131+DOT_PATH = "@DOT_PATH@"
132
133 # The DOTFILE_DIRS tag can be used to specify one or more directories that
134 # contain dot files that are included in the documentation (see the \dotfile
135
136=== modified file 'data/CMakeLists.txt'
137--- data/CMakeLists.txt 2016-05-29 09:27:35 +0000
138+++ data/CMakeLists.txt 2016-06-12 13:59:22 +0000
139@@ -53,13 +53,16 @@
140 ENDIF()
141
142 # install Scenery3d shaders
143+IF(USE_PLUGIN_SCENERY3D)
144 INSTALL(DIRECTORY shaders/ DESTINATION share/${PACKAGE}/data/shaders FILES_MATCHING
145- PATTERN "s3d_*.vert" PATTERN "s3d_*.geom" PATTERN "s3d_*.frag")
146-
147+ PATTERN "s3d_*.vert"
148+ PATTERN "s3d_*.geom"
149+ PATTERN "s3d_*.frag")
150 # install Scenery3D docs for Windows
151 IF(WIN32)
152 INSTALL(FILES ../plugins/Scenery3d/doc/Scenery3d.pdf DESTINATION share/${PACKAGE}/data)
153 ENDIF(WIN32)
154+ENDIF()
155
156 IF (BUILD_FOR_MAEMO)
157 INSTALL(FILES maemo/stellarium.desktop DESTINATION /usr/share/applications/hildon)
158
159=== modified file 'data/gui/normalStyle.css'
160--- data/gui/normalStyle.css 2015-08-18 06:29:08 +0000
161+++ data/gui/normalStyle.css 2016-06-12 13:59:22 +0000
162@@ -149,7 +149,7 @@
163 font-size: 12px;
164 }
165
166-QLineEdit[enabled="false"] {
167+QLineEdit:disabled {
168 background: rgb(90, 90, 90);
169 }
170
171
172=== modified file 'doc/DoxygenLayout.xml'
173--- doc/DoxygenLayout.xml 2014-06-22 14:08:40 +0000
174+++ doc/DoxygenLayout.xml 2016-06-12 13:59:22 +0000
175@@ -18,7 +18,7 @@
176 <tab type="user" url="@ref scripting" visible="yes" title="Scripting" intro=""/>
177 <tab type="user" url="@ref plugins" visible="yes" title="Plugins" intro=""/>
178 <tab type="user" url="@ref fileStructure" visible="yes" title="File Structure" intro=""/>
179- <tab type="files" visible="no" title="">
180+ <tab type="files" visible="yes" title="">
181 <tab type="filelist" visible="yes" title="" intro=""/>
182 <tab type="globals" visible="yes" title="" intro=""/>
183 </tab>
184
185=== modified file 'doc/doxygen.css'
186--- doc/doxygen.css 2015-06-08 20:08:26 +0000
187+++ doc/doxygen.css 2016-06-12 13:59:22 +0000
188@@ -1193,7 +1193,8 @@
189 float: right;
190 height: auto;
191 margin: 0 20px 10px 10px;
192- width: 200px;
193+ min-width: 200px;
194+ max-width: 400px;
195 }
196
197 div.toc li {
198
199=== modified file 'doc/mainpage.doxygen'
200--- doc/mainpage.doxygen 2016-02-25 17:31:00 +0000
201+++ doc/mainpage.doxygen 2016-06-12 13:59:22 +0000
202@@ -32,9 +32,9 @@
203 <ul>
204 <li>the main loop and main widget classes @em StelMainWindow and @em StelMainGraphicsView. Those classes have a single instance which is created at startup by the main() function. They perform various tasks such as the creation of the main program window and openGL context, the creation of the stellarium core, the creation of the GUI. After initialization, they manage user's input event propagation and event loop. There are heavily based on %Qt features.</li>
205 <li>the core which provides a number of generic services and features to the other components. The main class is the StelApp singleton class which is used everywhere in the code to access other elements. It is the StelApp instance which creates all the main core services and modules at initialization. Example services are OpenGL textures management with the StelTextureMgr, font management with the StelFontMgr, sky images management (images which have a fixed position in the sky) with the StelSkyImageMgr etc.. Two especially important manager classes (the ones with the "Mgr" suffix) are the StelModuleMgr and StelCore classes: the first one manages the collection of StelModule instances which are registered in the program (see next point for more info on what a StelModule is). The second one provides performance critical features for rendering various elements using openGL, or for computing coordinate transformation and other mathematical services.</li>
206-<li>a collection of StelModule instances which display the main elements of the program such as planets and stars. Each StelModule should be registered to the StelModuleMgr. Because many components of Stellarium derive from the StelModule class, it is possible for the main loop to treat them generically by calling their standard methods such StelModule::update() and StelModule::draw() at each program iteration. It also allows other program components to access them by name. StelModule can also be loaded dynamically by Stellarium, which is the standard way of creating @ref plugins.</li>
207-<li>the Graphical User Interface (StelGui). It is based on styled %Qt widgets which are rendered directly in the openGL window. Users actions trigger signals which are connected to core and StelModules slots.</li>
208-<li>the script engine (StelScriptMgr) allows scripts to calls slots from the core and StelModules slots.</li>
209+<li>a collection of StelModule instances which display the main elements of the program such as planets and stars. Each StelModule should be registered to the StelModuleMgr. Because many components of Stellarium derive from the StelModule class, it is possible for the main loop to treat them generically by calling their standard methods such StelModule::update() and StelModule::draw() at each program iteration. It also allows other program components to access them by name. StelProperty can be used to access all defined static properties (see the [Qt property system](https://doc.qt.io/qt-5/properties.html) for more information) of all registered StelModule instances. StelModule can also be loaded dynamically by Stellarium, which is the standard way of creating @ref plugins. StelAction instances can be used to define actions that can be triggered by the user through UI controls or key combinations.</li>
210+<li>the Graphical User Interface (StelGui). It is based on styled %Qt widgets which are rendered directly in the openGL window. Users actions can trigger signals which are connected to core and StelModules slots. Many UI controls can also be directly connected to StelAction and/or StelProperty instances to reduce the amount of boilerplate code required to link UI changes to the back-end modules and vice-versa.</li>
211+<li>the script engine (StelScriptMgr) allows user scripts based on QtScript (a JavaScript dialect) to access properties and calls slots from the core and StelModule instances.</li>
212 </ul>
213 @image html stellarium-architecture.png
214
215
216=== modified file 'doc/plugIns.doxygen'
217--- doc/plugIns.doxygen 2016-04-21 06:48:03 +0000
218+++ doc/plugIns.doxygen 2016-06-12 13:59:22 +0000
219@@ -65,6 +65,7 @@
220 - @ref meteorShowers
221 - @ref pointerCoordinates
222 - @ref archaeoLines
223+ - @ref remoteControl
224
225 You can find some untechnical details on our wiki [Plugins](http://www.stellarium.org/wiki/index.php/Plugins) page.
226
227
228=== added file 'guide/pictures/remote.png'
229Binary files guide/pictures/remote.png 1970-01-01 00:00:00 +0000 and guide/pictures/remote.png 2016-06-12 13:59:22 +0000 differ
230=== added file 'guide/pictures/remote_web.png'
231Binary files guide/pictures/remote_web.png 1970-01-01 00:00:00 +0000 and guide/pictures/remote_web.png 2016-06-12 13:59:22 +0000 differ
232=== modified file 'guide/plg_interfaces.tex'
233--- guide/plg_interfaces.tex 2016-05-05 23:42:27 +0000
234+++ guide/plg_interfaces.tex 2016-06-12 13:59:22 +0000
235@@ -373,7 +373,101 @@
236 \section{Remote Control}
237 \label{sec:plugin:RemoteControl}
238
239-[This will come as user documentation from SoCiS2015 work]
240+The Remote Control plugin was developed in 2015 during the
241+\href{http://sophia.estec.esa.int/socis/}{ESA Summer of Code in Space}
242+initiative. It enables the user to control Stellarium through an external web
243+interface using a standard web browser like Firefox or Chrome, instead of using
244+the main GUI. This works on the same computer Stellarium runs as well as over
245+the network. Even more, multiple "remote controls" can access the same
246+Stellarium instance at the same time, without getting in the way of each other.
247+Much of the functionality the main interface provides is already available
248+through it, and it is still getting extended.
249+
250+The plugin may be useful for presentation scenarios, hiding the GUI from the
251+audience and allowing the presenter to change settings on a separate monitor
252+without showing distracting dialog windows. It also allows to start and stop
253+scripts remotely. Because the web interface can be customized (or completely
254+replaced) with some knowledge of HTML, CSS and JavaScript, another possibility
255+is a kiosk mode, where untrusted users can execute a variety of predefined
256+actions (like starting recorded tours) without having access to all Stellarium
257+settings. The web API can also be accessed directly (without using a browser
258+and the HTML interface), allowing control of Stellarium with external programs
259+and scripts using HTTP calls like with the tools \file{wget} and \file{curl}.
260+
261+\subsection{Using the plugin}
262+\label{sec:plugins:RemoteControl:using}
263+
264+\begin{figure}[h]
265+\centering\includegraphics[width=\columnwidth]{remote_web}
266+\caption{The default remote control web interface}
267+\end{figure}
268+
269+After enabling the plugin, you can set it up through the configuration dialog.
270+When ``Enable automatically on startup'' is checked (it is by default), the web
271+server is automatically started whenever Stellarium starts. You can also
272+manually start/stop the server using the ``Server enabled'' checkbox and the
273+button \includegraphics[scale=0.5]{remote} in the toolbar.
274+
275+The plugin starts a HTTP server on the specified port. The default port is
276+8090, so you can try to reach the remote control after enabling it by starting
277+a browser on the same computer and entering \url{http://localhost:8090} in the
278+address bar. When trying to access the remote control from another computer,
279+you need the IP address or the hostname of the server on which Stellarium runs.
280+The plugin shows the locally detected address, but depending on your network or
281+if you need external access you might need to use a different one
282+--- contact your network administrator if you need help with that.
283+
284+The access to the remote control may optionally be restricted with a simple
285+password.
286+
287+\textbf{Warning:} \emph{currently no network encryption is used, meaning that
288+an attacker having access to your network can easily find out the password by
289+waiting for a user entering it. Access from the Internet to the
290+plugin should generally be restricted, except if countermeasures such as VPN
291+usage are taken! If you are in a home network using NAT (network access
292+translation), this should be enough for basic security except if port
293+forwarding or a DMZ is configured.}
294+
295+If you are familiar with the main Stellarium interface, you should easily find
296+your way around the web interface. Tabs at the top allow access to
297+different settings and controls. The remote control automatically uses the
298+same language as set in the main program.
299+
300+The contents of the various tabs:
301+\begin{description}
302+\item[Main] Contains the time controls and most of the buttons of the
303+main bottom toolbar. An additional control allows moving the view like when
304+dragging the mouse or using the arrow keys in Stellarium, and a slider enables
305+the changing of the field of view. There are also buttons to quickly execute
306+time jumps using the commonly used astronomical time intervals.
307+\item[Selection] Allows searching and selecting objects like in \autoref{sec:gui:search}.
308+SIMBAD search is also supported. Quick select buttons are available for the
309+primary solar system objects. It also displays the information text for current
310+selection.
311+\item[Sky] Settings related to the sky display as shown in the ``View'' dialog
312+as shown in \autoref{sec:gui:view:sky}.
313+\item[DSO] The deep-sky object catalog, filter and display settings like in
314+\autoref{sec:gui:view:markings}.
315+\item[Landscape] Changing and configuring the background landscape, see
316+\autoref{sec:gui:view:landscape}
317+\item[Actions and scripts] Lists all registered actions, and allows starting
318+and stopping of scripts (\autoref{ch:scripting}). If there is no button for the
319+action you want in another tab, you can find all actions which can be
320+configured as a keyboard shortcut (\autoref{sec:gui:configuration}) here.
321+\item[Location] Allows changing the location, like in
322+\autoref{sec:gui:location}. Custom location saving is currently not
323+supported.
324+\item[Projection] Switch the projection method used, like \autoref{sec:gui:view:markings}.
325+\end{description}
326+
327+\subsection{Developer information}
328+\label{sec:plugins:RemoteControl:developer}
329+
330+If you are a developer and would like to add functionality to the Remote
331+Control API, customize the web interface or access the API through another
332+program, further information can be found in the
333+\href{http://stellarium.org/doc-plugins/head/}{plugin's developer
334+documentation}.
335
336
337 % \newpage
338
339=== modified file 'plugins/ArchaeoLines/src/ArchaeoLines.cpp'
340--- plugins/ArchaeoLines/src/ArchaeoLines.cpp 2015-12-29 13:15:57 +0000
341+++ plugins/ArchaeoLines/src/ArchaeoLines.cpp 2016-06-12 13:59:22 +0000
342@@ -89,7 +89,7 @@
343 objMgr=GETSTELMODULE(StelObjectMgr);
344 Q_ASSERT(objMgr);
345
346- // optimize readabiity so that each upper line of the lunistice doubles is labeled.
347+ // optimize readability so that each upper line of the lunistice doubles is labeled.
348 equinoxLine = new ArchaeoLine(ArchaeoLine::Equinox, 0.0);
349 northernSolsticeLine = new ArchaeoLine(ArchaeoLine::Solstices, 23.50);
350 southernSolsticeLine = new ArchaeoLine(ArchaeoLine::Solstices, -23.50);
351@@ -116,6 +116,7 @@
352
353 configDialog = new ArchaeoLinesDialog();
354 conf = StelApp::getInstance().getSettings();
355+
356 }
357
358 ArchaeoLines::~ArchaeoLines()
359@@ -188,7 +189,8 @@
360 StelApp& app = StelApp::getInstance();
361
362 // Create action for enable/disable & hook up signals
363- addAction("actionShow_Archaeo_Lines", N_("ArchaeoLines"), N_("ArchaeoLines"), "enabled", "Ctrl+U");
364+ QString section=N_("ArchaeoLines");
365+ addAction("actionShow_Archaeo_Lines", section, N_("ArchaeoLines"), "enabled", "Ctrl+U");
366
367 // Add a toolbar button
368 try
369@@ -208,6 +210,16 @@
370 {
371 qWarning() << "WARNING: unable to create toolbar button for ArchaeoLines plugin: " << e.what();
372 }
373+ addAction("actionAL_showEquinoxLine", section, N_("Show Line for Equinox"), "flagShowEquinox" ); // No Shortcuts configured.
374+ addAction("actionAL_showSolsticeLines", section, N_("Show Line for Solstices"), "flagShowSolstices" ); // No Shortcuts configured.
375+ addAction("actionAL_showCrossquarterLines", section, N_("Show Line for Crossquarter"), "flagShowCrossquarters" ); // No Shortcuts configured.
376+ addAction("actionAL_showMajorStandstillLines", section, N_("Show Line for Major Standstill"), "flagShowMajorStandstills"); // No Shortcuts configured.
377+ addAction("actionAL_showMinorStandstillLines", section, N_("Show Line for Minor Standstill"), "flagShowMinorStandstills"); // No Shortcuts configured.
378+ addAction("actionAL_showZenithPassageLine", section, N_("Show Line for Zenith Passage"), "flagShowZenithPassage" ); // No Shortcuts configured.
379+ addAction("actionAL_showNadirPassageLine", section, N_("Show Line for Nadir Passage"), "flagShowNadirPassage" ); // No Shortcuts configured.
380+ addAction("actionAL_showSelectedObjectLine", section, N_("Show Line for Selected Object"), "flagShowSelectedObject" ); // No Shortcuts configured.
381+ addAction("actionAL_showCurrentSunLine", section, N_("Show Line for Current Sun"), "flagShowCurrentSun" ); // No Shortcuts configured.
382+ addAction("actionAL_showCurrentMoonLine", section, N_("Show Line for Current Moon"), "flagShowCurrentMoon" ); // No Shortcuts configured.
383 }
384
385 void ArchaeoLines::update(double deltaTime)
386@@ -450,7 +462,7 @@
387 // indicators for current declinations (those move fast over days...)
388 showCurrentSun(conf->value("ArchaeoLines/show_current_sun", true).toBool());
389 showCurrentMoon(conf->value("ArchaeoLines/show_current_moon", true).toBool());
390- showCurrentPlanet(conf->value("ArchaeoLines/show_current_planet", "none").toString());
391+ showCurrentPlanetNamed(conf->value("ArchaeoLines/show_current_planet", "none").toString());
392
393 enableArchaeoLines(conf->value("ArchaeoLines/enable_at_startup", false).toBool());
394 }
395@@ -526,15 +538,20 @@
396
397 void ArchaeoLines::showCurrentPlanet(ArchaeoLine::Line l)
398 {
399- enumShowCurrentPlanet=l;
400- const char *planetStrings[]={"none", "Mercury", "Venus", "Mars", "Jupiter", "Saturn"};
401-
402- conf->setValue("ArchaeoLines/show_current_planet", planetStrings[l-ArchaeoLine::CurrentPlanetNone]);
403- currentPlanetLine->setLineType(enumShowCurrentPlanet);
404- currentPlanetLine->setDisplayed(enumShowCurrentPlanet != ArchaeoLine::CurrentPlanetNone);
405+ if(l!=enumShowCurrentPlanet)
406+ {
407+ enumShowCurrentPlanet=l;
408+ const char *planetStrings[]={"none", "Mercury", "Venus", "Mars", "Jupiter", "Saturn"};
409+
410+ conf->setValue("ArchaeoLines/show_current_planet", planetStrings[l-ArchaeoLine::CurrentPlanetNone]);
411+ currentPlanetLine->setLineType(enumShowCurrentPlanet);
412+ currentPlanetLine->setDisplayed(enumShowCurrentPlanet != ArchaeoLine::CurrentPlanetNone);
413+
414+ emit currentPlanetChanged(l);
415+ }
416 }
417
418-void ArchaeoLines::showCurrentPlanet(QString planet)
419+void ArchaeoLines::showCurrentPlanetNamed(QString planet)
420 {
421 if (planet=="none")
422 enumShowCurrentPlanet=ArchaeoLine::CurrentPlanetNone;
423
424=== modified file 'plugins/ArchaeoLines/src/ArchaeoLines.hpp'
425--- plugins/ArchaeoLines/src/ArchaeoLines.hpp 2015-08-03 13:17:06 +0000
426+++ plugins/ArchaeoLines/src/ArchaeoLines.hpp 2016-06-12 13:59:22 +0000
427@@ -77,6 +77,10 @@
428 Q_OBJECT
429 Q_PROPERTY(Vec3f color READ getColor WRITE setColor)
430 Q_PROPERTY(bool flagLabel READ isLabelVisible WRITE setLabelVisible)
431+
432+ //Need to register Enum with Qt to be able to use it as Q_PROPERTY
433+ //or in signals/slots
434+ Q_ENUMS(Line)
435 public:
436 enum Line {
437 Equinox,
438@@ -174,7 +178,8 @@
439 WRITE showCurrentMoon)
440 Q_PROPERTY(ArchaeoLine::Line enumShowCurrentPlanet
441 READ whichCurrentPlanetDisplayed
442- WRITE showCurrentPlanet)
443+ WRITE showCurrentPlanet
444+ NOTIFY currentPlanetChanged)
445
446 public:
447 ArchaeoLines();
448@@ -190,19 +195,7 @@
449 virtual double getCallOrder(StelModuleActionName actionName) const;
450 virtual void handleKeys(class QKeyEvent* event){event->setAccepted(false);}
451 virtual bool configureGui(bool show=true);
452- bool isEnabled() const {return flagShowArchaeoLines;}
453 bool isDmsFormat() const { return flagUseDmsFormat; } // NOT SURE IF USEFUL
454- bool isEquinoxDisplayed() const {return flagShowEquinox;}
455- bool isSolsticesDisplayed() const {return flagShowSolstices;}
456- bool isCrossquartersDisplayed() const {return flagShowCrossquarters;}
457- bool isMajorStandstillsDisplayed() const {return flagShowMajorStandstills;}
458- bool isMinorStandstillsDisplayed() const {return flagShowMinorStandstills;}
459- bool isZenithPassageDisplayed() const {return flagShowZenithPassage;}
460- bool isNadirPassageDisplayed() const {return flagShowNadirPassage;}
461- bool isSelectedObjectDisplayed() const {return flagShowSelectedObject;}
462- bool isCurrentSunDisplayed() const {return flagShowCurrentSun;}
463- bool isCurrentMoonDisplayed() const {return flagShowCurrentMoon;}
464- ArchaeoLine::Line whichCurrentPlanetDisplayed() const {return enumShowCurrentPlanet;}
465
466 //! Restore the plug-in's settings to the default state.
467 //! Replace the plug-in's settings in Stellarium's configuration file
468@@ -217,11 +210,27 @@
469 //! @see restoreDefaultSettings()
470 void loadSettings();
471
472+signals:
473+ void currentPlanetChanged(ArchaeoLine::Line l); // meaningful only CurrentPlanetNone...CurrentPlanetSaturn.
474
475 public slots:
476 void enableArchaeoLines(bool b);
477 //void useDmsFormat(bool b);
478
479+ bool isEnabled() const {return flagShowArchaeoLines;}
480+ bool isEquinoxDisplayed() const {return flagShowEquinox;}
481+ bool isSolsticesDisplayed() const {return flagShowSolstices;}
482+ bool isCrossquartersDisplayed() const {return flagShowCrossquarters;}
483+ bool isMajorStandstillsDisplayed() const {return flagShowMajorStandstills;}
484+ bool isMinorStandstillsDisplayed() const {return flagShowMinorStandstills;}
485+ bool isZenithPassageDisplayed() const {return flagShowZenithPassage;}
486+ bool isNadirPassageDisplayed() const {return flagShowNadirPassage;}
487+ bool isSelectedObjectDisplayed() const {return flagShowSelectedObject;}
488+ bool isCurrentSunDisplayed() const {return flagShowCurrentSun;}
489+ bool isCurrentMoonDisplayed() const {return flagShowCurrentMoon;}
490+ ArchaeoLine::Line whichCurrentPlanetDisplayed() const {return enumShowCurrentPlanet;}
491+
492+
493 void showEquinox(bool b);
494 void showSolstices(bool b);
495 void showCrossquarters(bool b);
496@@ -233,7 +242,7 @@
497 void showCurrentSun(bool b);
498 void showCurrentMoon(bool b);
499 void showCurrentPlanet(ArchaeoLine::Line l); // Allowed values for l: CurrentPlanetNone...CurrentPlanetSaturn.
500- void showCurrentPlanet(QString planet); // Allowed values for planet: "none", "Mercury", "Venus", "Mars", "Jupiter", "Saturn".
501+ void showCurrentPlanetNamed(QString planet); // Allowed values for planet: "none", "Mercury", "Venus", "Mars", "Jupiter", "Saturn".
502
503 // called by the dialog GUI, converts GUI's QColor (0..255) to Stellarium's Vec3f float color.
504 void setLineColor(ArchaeoLine::Line whichLine, QColor color);
505
506=== modified file 'plugins/ArchaeoLines/src/gui/ArchaeoLinesDialog.cpp'
507--- plugins/ArchaeoLines/src/gui/ArchaeoLinesDialog.cpp 2016-01-22 11:05:08 +0000
508+++ plugins/ArchaeoLines/src/gui/ArchaeoLinesDialog.cpp 2016-06-12 13:59:22 +0000
509@@ -90,7 +90,8 @@
510 ui->currentMoonCheckBox->setChecked(al->isCurrentMoonDisplayed());
511 connect(ui->currentMoonCheckBox, SIGNAL(toggled(bool)), al, SLOT(showCurrentMoon(bool)));
512 // Planet ComboBox requires special handling!
513- ui->currentPlanetComboBox->setCurrentIndex(al->whichCurrentPlanetDisplayed()-ArchaeoLine::CurrentPlanetNone);
514+ setCurrentPlanetFromApp();
515+ connect(al, SIGNAL(currentPlanetChanged(ArchaeoLine::Line)), this, SLOT(setCurrentPlanetFromApp()));
516 connect(ui->currentPlanetComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setCurrentPlanetFromGUI(int)));
517
518 equinoxColor = al->getLineColor(ArchaeoLine::Equinox);
519@@ -177,6 +178,12 @@
520 al->showCurrentPlanet((ArchaeoLine::Line) (ArchaeoLine::CurrentPlanetNone+index));
521 }
522
523+void ArchaeoLinesDialog::setCurrentPlanetFromApp()
524+{
525+ Q_ASSERT(al);
526+ ui->currentPlanetComboBox->setCurrentIndex(al->whichCurrentPlanetDisplayed()-ArchaeoLine::CurrentPlanetNone);
527+}
528+
529
530 void ArchaeoLinesDialog::setAboutHtml(void)
531 {
532
533=== modified file 'plugins/ArchaeoLines/src/gui/ArchaeoLinesDialog.hpp'
534--- plugins/ArchaeoLines/src/gui/ArchaeoLinesDialog.hpp 2015-05-30 19:56:47 +0000
535+++ plugins/ArchaeoLines/src/gui/ArchaeoLinesDialog.hpp 2016-06-12 13:59:22 +0000
536@@ -103,6 +103,7 @@
537 void resetArchaeoLinesSettings();
538 //! setting planet requires a small function to link Combobox indices to line IDs.
539 void setCurrentPlanetFromGUI(int index);
540+ void setCurrentPlanetFromApp();
541
542 };
543
544
545=== modified file 'plugins/Oculars/src/Oculars.cpp'
546--- plugins/Oculars/src/Oculars.cpp 2016-06-11 17:54:59 +0000
547+++ plugins/Oculars/src/Oculars.cpp 2016-06-12 13:59:22 +0000
548@@ -126,7 +126,7 @@
549 flagMoonScale(false),
550 maxEyepieceAngle(0.0),
551 requireSelection(true),
552- flagLimitMagnitude(false),
553+ flagLimitMagnitude(false),
554 useMaxEyepieceAngle(true),
555 guiPanelEnabled(false),
556 flagDecimalDegrees(false),
557@@ -258,7 +258,7 @@
558 lens->writeToSettings(settings, index);
559 index++;
560 }
561-
562+
563 settings->setValue("ocular_count", oculars.count());
564 settings->setValue("telescope_count", telescopes.count());
565 settings->setValue("ccd_count", ccds.count());
566@@ -283,22 +283,22 @@
567 if (selectedCCDIndex > ccds.count())
568 {
569 qWarning() << "Oculars: the selected sensor index of "
570- << selectedCCDIndex << " is greater than the sensor count of "
571- << ccds.count() << ". Module disabled!";
572+ << selectedCCDIndex << " is greater than the sensor count of "
573+ << ccds.count() << ". Module disabled!";
574 ready = false;
575 }
576 if (selectedOcularIndex > oculars.count())
577 {
578 qWarning() << "Oculars: the selected ocular index of "
579- << selectedOcularIndex << " is greater than the ocular count of "
580- << oculars.count() << ". Module disabled!";
581+ << selectedOcularIndex << " is greater than the ocular count of "
582+ << oculars.count() << ". Module disabled!";
583 ready = false;
584 }
585 else if (selectedTelescopeIndex > telescopes.count())
586 {
587 qWarning() << "Oculars: the selected telescope index of "
588- << selectedTelescopeIndex << " is greater than the telescope count of "
589- << telescopes.count() << ". Module disabled!";
590+ << selectedTelescopeIndex << " is greater than the telescope count of "
591+ << telescopes.count() << ". Module disabled!";
592 ready = false;
593 }
594
595@@ -785,7 +785,7 @@
596 }
597 }
598 guiPanelEnabled = enable;
599- settings->setValue("enable_control_panel", enable);
600+ settings->setValue("enable_control_panel", enable);
601 settings->sync();
602 }
603
604@@ -833,7 +833,7 @@
605 if (oculars.isEmpty())
606 {
607 selectedOcularIndex = -1;
608- actionShowOcular->setChecked(false);
609+ enableOcular(false);
610 }
611 else
612 {
613@@ -847,8 +847,8 @@
614 if (telescopes.isEmpty())
615 {
616 selectedTelescopeIndex = -1;
617- actionShowOcular->setChecked(false);
618- actionShowSensor->setChecked(false);
619+ enableOcular(false);
620+ toggleCCD(false);
621 }
622 else
623 {
624@@ -862,7 +862,7 @@
625 if (ccds.isEmpty())
626 {
627 selectedCCDIndex = -1;
628- actionShowSensor->setChecked(false);
629+ toggleCCD(false);
630 }
631 else
632 {
633@@ -895,8 +895,7 @@
634 // Close the sensor view if it's displayed
635 if (flagShowCCD)
636 {
637- if (actionShowSensor->isChecked())
638- actionShowSensor->setChecked(false);
639+ toggleCCD(false);
640 flagShowCCD = false;
641 selectedCCDIndex = -1;
642 }
643@@ -904,8 +903,7 @@
644 // Close the Telrad sight if it's displayed
645 if (flagShowTelrad)
646 {
647- if (actionShowTelrad->isChecked())
648- actionShowTelrad->setChecked(false);
649+ toggleTelrad(false);
650 }
651
652 // Check to ensure that we have enough oculars & telescopes, as they may have been edited in the config dialog
653@@ -954,10 +952,6 @@
654 usageMessageLabelID = labelManager->labelScreen(labelText, xPosition, yPosition,
655 true, font.pixelSize(), tcolor);
656 }
657- // we didn't accept the new status - make sure the toolbar button reflects this
658- disconnect(actionShowOcular, SIGNAL(toggled(bool)), this, SLOT(enableOcular(bool)));
659- actionShowOcular->setChecked(false);
660- connect(actionShowOcular, SIGNAL(toggled(bool)), this, SLOT(enableOcular(bool)));
661 }
662 else
663 {
664@@ -972,6 +966,8 @@
665 guiPanel->showOcularGui();
666 }
667 }
668+
669+ emit enableOcularChanged(flagShowOculars);
670 }
671
672 void Oculars::decrementCCDIndex()
673@@ -1363,14 +1359,10 @@
674 flagShowCCD = false;
675 selectedCCDIndex = -1;
676 show = false;
677- if (actionShowSensor->isChecked())
678- {
679- actionShowSensor->setChecked(false);
680- }
681 }
682
683 StelCore *core = StelApp::getInstance().getCore();
684- StelMovementMgr *movementManager = core->getMovementMgr();
685+ StelMovementMgr *movementManager = core->getMovementMgr();
686 StelSkyDrawer *skyManager = core->getSkyDrawer();
687 skyManager->setAbsoluteStarScale(absoluteStarScale);
688 if (show)
689@@ -1378,18 +1370,10 @@
690 initialFOV = movementManager->getCurrentFov();
691 //Mutually exclusive with the ocular mode
692 hideUsageMessageIfDisplayed();
693- if (flagShowOculars)
694- {
695- if (actionShowOcular->isChecked())
696- {
697- actionShowOcular->setChecked(false);
698- }
699- }
700+ enableOcular(false);
701
702 if (flagShowTelrad) {
703- if (actionShowTelrad->isChecked()) {
704- actionShowTelrad->setChecked(false);
705- }
706+ toggleTelrad(false);
707 }
708
709 if (selectedTelescopeIndex < 0)
710@@ -1402,6 +1386,7 @@
711 }
712 flagShowCCD = true;
713 setScreenFOVForCCD();
714+
715 // Change relative scale for stars
716 // TODO: Finding experimental value for better rendering
717 skyManager->setRelativeStarScale(0.6);
718@@ -1417,7 +1402,7 @@
719
720 skyManager->setRelativeStarScale(relativeStarScale);
721 movementManager->setFlagTracking(false);
722- //Zoom out
723+ //Zoom out
724 if (getFlagInitFovUsage())
725 movementManager->zoomTo(movementManager->getInitFov());
726 else
727@@ -1434,51 +1419,42 @@
728 guiPanel->foldGui();
729 }
730 }
731+
732+ emit enableCCDChanged(flagShowCCD);
733 }
734
735 void Oculars::toggleCCD()
736 {
737- if (flagShowCCD)
738- {
739- toggleCCD(false);
740- }
741- else
742- {
743- toggleCCD(true);
744- }
745+ toggleCCD(!flagShowCCD);
746 }
747
748 void Oculars::toggleCrosshairs(bool show)
749 {
750- if (show && flagShowOculars)
751- {
752- flagShowCrosshairs = true;
753- }
754- else
755- {
756- flagShowCrosshairs = false;
757+ if(show != flagShowCrosshairs)
758+ {
759+ flagShowCrosshairs = show;
760+ emit enableCrosshairsChanged(show);
761 }
762 }
763
764 void Oculars::toggleTelrad(bool show)
765 {
766- if (show)
767+ if(show!=flagShowTelrad)
768 {
769- hideUsageMessageIfDisplayed();
770- if (actionShowOcular->isChecked())
771- actionShowOcular->setChecked(false);
772- if (actionShowSensor->isChecked())
773- actionShowSensor->setChecked(false);
774+ if (show)
775+ {
776+ hideUsageMessageIfDisplayed();
777+ enableOcular(false);
778+ toggleCCD(false);
779+ }
780+ flagShowTelrad = show;
781+ emit enableTelradChanged(flagShowTelrad);
782 }
783- flagShowTelrad = show;
784 }
785
786 void Oculars::toggleTelrad()
787 {
788- if (flagShowTelrad)
789- toggleTelrad(false);
790- else
791- toggleTelrad(true);
792+ toggleTelrad(!flagShowTelrad);
793 }
794
795 /* ****************************************************************************************************************** */
796@@ -1493,8 +1469,7 @@
797 Q_ASSERT(gui);
798
799 QString ocularsGroup = N_("Oculars");
800- actionShowOcular = addAction("actionShow_Ocular", ocularsGroup, N_("Ocular view"), "enableOcular(bool)", "Ctrl+O");
801- actionShowOcular->setChecked(flagShowOculars);
802+ actionShowOcular = addAction("actionShow_Ocular", ocularsGroup, N_("Ocular view"), "enableOcular", "Ctrl+O");
803 // Make a toolbar button
804 try
805 {
806@@ -1510,9 +1485,9 @@
807 }
808
809 actionMenu = addAction("actionShow_Ocular_Menu", ocularsGroup, N_("Oculars popup menu"), "displayPopupMenu()", "Alt+O");
810- actionShowCrosshairs = addAction("actionShow_Ocular_Crosshairs", ocularsGroup, N_("Show crosshairs"), "toggleCrosshairs(bool)", "Alt+C");
811- actionShowSensor = addAction("actionShow_Sensor", ocularsGroup, N_("Image sensor frame"), "toggleCCD(bool)");
812- actionShowTelrad = addAction("actionShow_Telrad", ocularsGroup, N_("Telrad sight"), "toggleTelrad(bool)", "Ctrl+B");
813+ actionShowCrosshairs = addAction("actionShow_Ocular_Crosshairs", ocularsGroup, N_("Show crosshairs"), "enableCrosshairs", "Alt+C");
814+ actionShowSensor = addAction("actionShow_Sensor", ocularsGroup, N_("Image sensor frame"), "enableCCD");
815+ actionShowTelrad = addAction("actionShow_Telrad", ocularsGroup, N_("Telrad sight"), "enableTelrad", "Ctrl+B");
816 actionConfiguration = addAction("actionOpen_Oculars_Configuration", ocularsGroup, N_("Oculars plugin configuration"), ocularDialog, "visible");
817 // Select next telescope via keyboard
818 addAction("actionShow_Telescope_Increment", ocularsGroup, N_("Select next telescope"), "incrementTelescopeIndex()", "");
819@@ -1556,11 +1531,11 @@
820
821 void Oculars::paintCCDBounds()
822 {
823- StelCore *core = StelApp::getInstance().getCore();
824+ StelCore *core = StelApp::getInstance().getCore();
825 StelProjector::StelProjectorParams params = core->getCurrentStelProjectorParams();
826 Lens *lens = selectedLensIndex >=0 ? lense[selectedLensIndex] : NULL;
827
828- const StelProjectorP projector = core->getProjection(StelCore::FrameEquinoxEqu);
829+ const StelProjectorP projector = core->getProjection(StelCore::FrameEquinoxEqu);
830 double screenFOV = params.fov;
831
832 // draw sensor rectangle
833@@ -1648,9 +1623,9 @@
834
835 //painter.setColor(0.60f, 0.20f, 0.20f, .5f);
836 painter.drawCircle(params.viewportCenter[0] * params.devicePixelsPerPixel,
837- params.viewportCenter[1] * params.devicePixelsPerPixel, in_oag_r);
838+ params.viewportCenter[1] * params.devicePixelsPerPixel, in_oag_r);
839 painter.drawCircle(params.viewportCenter[0] * params.devicePixelsPerPixel,
840- params.viewportCenter[1] * params.devicePixelsPerPixel, out_oag_r);
841+ params.viewportCenter[1] * params.devicePixelsPerPixel, out_oag_r);
842
843 QTransform oag_transform = QTransform().translate(params.viewportCenter[0] * params.devicePixelsPerPixel,
844 params.viewportCenter[1] * params.devicePixelsPerPixel).rotate(-(ccd->chipRotAngle() + polarAngle + ccd->prismPosAngle()));
845@@ -1786,8 +1761,8 @@
846 reticleTexture->getDimensions(textureWidth, textureHeight);
847
848 painter.drawSprite2dMode(params.viewportXywh[2] / 2 * params.devicePixelsPerPixel,
849- params.viewportXywh[3] / 2 * params.devicePixelsPerPixel,
850- inner, reticleRotation);
851+ params.viewportXywh[3] / 2 * params.devicePixelsPerPixel,
852+ inner, reticleRotation);
853 }
854
855 if (oculars[selectedOcularIndex]->hasPermanentCrosshair())
856@@ -1845,7 +1820,7 @@
857 void Oculars::paintText(const StelCore* core)
858 {
859 const StelProjectorP prj = core->getProjection(StelCore::FrameAltAz);
860- StelPainter painter(prj);
861+ StelPainter painter(prj);
862
863 // Get the current instruments
864 CCD *ccd = NULL;
865@@ -1922,7 +1897,7 @@
866 QString ocularFOVLabel = QString(q_("Ocular aFOV: %1")).arg(ocularFov);
867 painter.drawText(xPosition, yPosition, ocularFOVLabel);
868 yPosition-=lineHeight;
869-
870+
871 QString lensNumberLabel;
872 // Barlow and Shapley lens
873 if (lens != NULL) // it's null if lens is not selected (lens index = -1)
874@@ -1943,7 +1918,7 @@
875 }
876 painter.drawText(xPosition, yPosition, lensNumberLabel);
877 yPosition-=lineHeight;
878-
879+
880 // The telescope
881 QString telescopeString = "";
882 QString magString = "";
883@@ -2014,7 +1989,7 @@
884 .arg(name);
885 }
886 // The telescope
887- QString telescopeNumberLabel;
888+ QString telescopeNumberLabel;
889 if (telescopeName.isEmpty())
890 {
891 telescopeNumberLabel = QString(q_("Telescope #%1"))
892@@ -2051,7 +2026,7 @@
893 if (!src.copy(ocularIniPath))
894 {
895 qWarning() << "Oculars::validateIniFile cannot copy default_ocular.ini resource to [non-existing] "
896- + ocularIniPath;
897+ + ocularIniPath;
898 }
899 else
900 {
901@@ -2256,7 +2231,7 @@
902 }
903 telescope = telescopes[selectedTelescopeIndex];
904 core->setFlipHorz(telescope->isHFlipped());
905- core->setFlipVert(telescope->isVFlipped());
906+ core->setFlipVert(telescope->isVFlipped());
907 }
908
909 // Change relative and absolute scales for stars
910@@ -2308,7 +2283,7 @@
911 QMenu* Oculars::addLensSubmenu(QMenu* parent)
912 {
913 Q_ASSERT(parent);
914-
915+
916 QMenu *submenu = new QMenu(q_("&Lens"), parent);
917 submenu->addAction(q_("&Previous lens"), this, SLOT(decrementLensIndex()));
918 submenu->addAction(q_("&Next lens"), this, SLOT(incrementLensIndex()));
919@@ -2371,7 +2346,7 @@
920 void Oculars::setFlagDecimalDegrees(const bool b)
921 {
922 flagDecimalDegrees = b;
923- settings->setValue("use_decimal_degrees", b);
924+ settings->setValue("use_decimal_degrees", b);
925 settings->sync();
926 }
927
928
929=== modified file 'plugins/Oculars/src/Oculars.hpp'
930--- plugins/Oculars/src/Oculars.hpp 2016-06-11 17:54:59 +0000
931+++ plugins/Oculars/src/Oculars.hpp 2016-06-12 13:59:22 +0000
932@@ -75,6 +75,12 @@
933 class Oculars : public StelModule
934 {
935 Q_OBJECT
936+
937+ Q_PROPERTY(bool enableOcular READ getEnableOcular WRITE enableOcular NOTIFY enableOcularChanged)
938+ Q_PROPERTY(bool enableCrosshairs READ getEnableCrosshairs WRITE toggleCrosshairs NOTIFY enableCrosshairsChanged)
939+ Q_PROPERTY(bool enableCCD READ getEnableCCD WRITE toggleCCD NOTIFY enableCCDChanged)
940+ Q_PROPERTY(bool enableTelrad READ getEnableTelrad WRITE toggleTelrad NOTIFY enableTelradChanged)
941+
942 //BM: Temporary, until the GUI is finalized and some other method of getting
943 //info from the main class is implemented.
944 friend class OcularsGuiPanel;
945@@ -119,6 +125,7 @@
946 //! This method is called with we detect that our hot key is pressed. It handles
947 //! determining if we should do anything - based on a selected object.
948 void enableOcular(bool b);
949+ bool getEnableOcular() const { return flagShowOculars; }
950 void incrementCCDIndex();
951 void incrementOcularIndex();
952 void incrementTelescopeIndex();
953@@ -133,9 +140,12 @@
954 void toggleCCD(bool show);
955 //! Toggles the sensor frame overlay (overloaded for blind switching).
956 void toggleCCD();
957+ bool getEnableCCD() const { return flagShowCCD; }
958 void toggleCrosshairs(bool show = true);
959+ bool getEnableCrosshairs() const { return flagShowCrosshairs; }
960 //! Toggles the Telrad sight overlay.
961 void toggleTelrad(bool show);
962+ bool getEnableTelrad() const { return flagShowTelrad; }
963 //! Toggles the Telrad sight overlay (overloaded for blind switching).
964 void toggleTelrad();
965 void enableGuiPanel(bool enable = true);
966@@ -156,6 +166,10 @@
967 bool getFlagUseSemiTransparency(void) const;
968
969 signals:
970+ void enableOcularChanged(bool value);
971+ void enableCrosshairsChanged(bool value);
972+ void enableCCDChanged(bool value);
973+ void enableTelradChanged(bool value);
974 void selectedCCDChanged();
975 void selectedOcularChanged();
976 void selectedTelescopeChanged();
977@@ -166,7 +180,7 @@
978 void instrumentChanged();
979 void determineMaxEyepieceAngle();
980 void setRequireSelection(bool state);
981- void setScaleImageCircle(bool state);
982+ void setScaleImageCircle(bool state);
983 void setScreenFOVForCCD();
984 void retranslateGui();
985 void setStelStyle(const QString& style);
986
987=== modified file 'plugins/Oculars/src/gui/OcularsGuiPanel.cpp'
988--- plugins/Oculars/src/gui/OcularsGuiPanel.cpp 2016-03-04 15:04:20 +0000
989+++ plugins/Oculars/src/gui/OcularsGuiPanel.cpp 2016-06-12 13:59:22 +0000
990@@ -37,8 +37,8 @@
991 #include <QWidget>
992
993 OcularsGuiPanel::OcularsGuiPanel(Oculars* plugin,
994- QGraphicsWidget *parent,
995- Qt::WindowFlags wFlags):
996+ QGraphicsWidget *parent,
997+ Qt::WindowFlags wFlags):
998 QGraphicsWidget(parent, wFlags),
999 ocularsPlugin(plugin),
1000 parentWidget(parent),
1001@@ -58,56 +58,49 @@
1002 StelApp& stelApp = StelApp::getInstance();
1003 Q_ASSERT(ocularsPlugin->actionShowOcular);
1004 buttonOcular = new StelButton(buttonBar,
1005- QPixmap(":/ocular/bt_ocular_on.png"),
1006- QPixmap(":/ocular/bt_ocular_off.png"),
1007- QPixmap(),
1008- ocularsPlugin->actionShowOcular,
1009- true); //No background
1010+ QPixmap(":/ocular/bt_ocular_on.png"),
1011+ QPixmap(":/ocular/bt_ocular_off.png"),
1012+ QPixmap(),
1013+ ocularsPlugin->actionShowOcular,
1014+ true); //No background
1015 buttonOcular->setToolTip(ocularsPlugin->actionShowOcular->getText());
1016 buttonOcular->setParentItem(buttonBar);
1017
1018- //Hack to avoid buttonOcular being left "checked" if it has been toggled
1019- //without any object selected.
1020- disconnect(ocularsPlugin->actionShowOcular, SIGNAL(toggled(bool)),
1021- ocularsPlugin, SLOT(enableOcular(bool)));
1022- connect(ocularsPlugin->actionShowOcular, SIGNAL(toggled(bool)),
1023- ocularsPlugin, SLOT(enableOcular(bool)));
1024-
1025 Q_ASSERT(ocularsPlugin->actionShowCrosshairs);
1026 buttonCrosshairs = new StelButton(buttonBar,
1027- QPixmap(":/ocular/bt_crosshairs_on.png"),
1028- QPixmap(":/ocular/bt_crosshairs_off.png"),
1029- QPixmap(),
1030- ocularsPlugin->actionShowCrosshairs,
1031- true);
1032+ QPixmap(":/ocular/bt_crosshairs_on.png"),
1033+ QPixmap(":/ocular/bt_crosshairs_off.png"),
1034+ QPixmap(),
1035+ ocularsPlugin->actionShowCrosshairs,
1036+ true);
1037 buttonCrosshairs->setToolTip(ocularsPlugin->actionShowCrosshairs->getText());
1038 buttonCrosshairs->setVisible(false);
1039
1040 Q_ASSERT(ocularsPlugin->actionShowSensor);
1041 buttonCcd = new StelButton(buttonBar,
1042- QPixmap(":/ocular/bt_sensor_on.png"),
1043- QPixmap(":/ocular/bt_sensor_off.png"),
1044- QPixmap(),
1045- ocularsPlugin->actionShowSensor,
1046- true);
1047+ QPixmap(":/ocular/bt_sensor_on.png"),
1048+ QPixmap(":/ocular/bt_sensor_off.png"),
1049+ QPixmap(),
1050+ ocularsPlugin->actionShowSensor,
1051+ true);
1052 buttonCcd->setToolTip(ocularsPlugin->actionShowSensor->getText());
1053
1054 Q_ASSERT(ocularsPlugin->actionShowTelrad);
1055 buttonTelrad = new StelButton(buttonBar,
1056- QPixmap(":/ocular/bt_telrad_on.png"),
1057- QPixmap(":/ocular/bt_telrad_off.png"),
1058- QPixmap(),
1059- ocularsPlugin->actionShowTelrad,
1060- true);
1061+ QPixmap(":/ocular/bt_telrad_on.png"),
1062+ QPixmap(":/ocular/bt_telrad_off.png"),
1063+ QPixmap(),
1064+ ocularsPlugin->actionShowTelrad,
1065+ true);
1066 buttonTelrad->setToolTip(ocularsPlugin->actionShowTelrad->getText());
1067
1068 Q_ASSERT(ocularsPlugin->actionConfiguration);
1069 buttonConfiguration = new StelButton(buttonBar,
1070- QPixmap(":/ocular/bt_settings_on.png"),
1071- QPixmap(":/ocular/bt_settings_off.png"),
1072- QPixmap(),
1073- ocularsPlugin->actionConfiguration,
1074- true);
1075+ QPixmap(":/ocular/bt_settings_on.png"),
1076+ QPixmap(":/ocular/bt_settings_off.png"),
1077+ QPixmap(),
1078+ ocularsPlugin->actionConfiguration,
1079+ true);
1080 buttonConfiguration->setToolTip(ocularsPlugin->actionConfiguration->getText());
1081
1082 qreal buttonHeight = buttonOcular->boundingRect().height();
1083@@ -179,73 +172,63 @@
1084 QPixmap naOff(":/graphicGui/btTimeForward-off.png");
1085 QPixmap nextArrowOff = naOff.scaledToHeight(scale, Qt::SmoothTransformation);
1086
1087- StelAction* defaultAction = new StelAction(this);
1088- defaultAction->setCheckable(false);
1089 prevOcularButton = new StelButton(ocularControls,
1090- prevArrow,
1091- prevArrowOff,
1092- QPixmap(),
1093- defaultAction);
1094+ prevArrow,
1095+ prevArrowOff,
1096+ QPixmap());
1097 prevOcularButton->setToolTip(q_("Previous ocular"));
1098 nextOcularButton = new StelButton(ocularControls,
1099- nextArrow,
1100- nextArrowOff,
1101- QPixmap(),
1102- defaultAction);
1103+ nextArrow,
1104+ nextArrowOff,
1105+ QPixmap());
1106 nextOcularButton->setToolTip(q_("Next ocular"));
1107 prevLensButton = new StelButton(lensControls,
1108- prevArrow,
1109- prevArrowOff,
1110- QPixmap(),
1111- defaultAction);
1112+ prevArrow,
1113+ prevArrowOff,
1114+ QPixmap());
1115 prevLensButton->setToolTip(q_("Previous lens"));
1116 nextLensButton = new StelButton(lensControls,
1117- nextArrow,
1118- nextArrowOff,
1119- QPixmap(),
1120- defaultAction);
1121+ nextArrow,
1122+ nextArrowOff,
1123+ QPixmap());
1124 nextLensButton->setToolTip(q_("Next lens"));
1125 prevCcdButton = new StelButton(ccdControls,
1126- prevArrow,
1127- prevArrowOff,
1128- QPixmap(),
1129- defaultAction);
1130+ prevArrow,
1131+ prevArrowOff,
1132+ QPixmap());
1133 prevCcdButton->setToolTip(q_("Previous CCD frame"));
1134 nextCcdButton = new StelButton(ccdControls,
1135- nextArrow,
1136- nextArrowOff,
1137- QPixmap(),
1138- defaultAction);
1139+ nextArrow,
1140+ nextArrowOff,
1141+ QPixmap());
1142 nextCcdButton->setToolTip(q_("Next CCD frame"));
1143 prevTelescopeButton = new StelButton(telescopeControls,
1144- prevArrow,
1145- prevArrowOff,
1146- QPixmap(),
1147- defaultAction);
1148+ prevArrow,
1149+ prevArrowOff,
1150+ QPixmap());
1151 prevTelescopeButton->setToolTip(q_("Previous telescope"));
1152 nextTelescopeButton = new StelButton(telescopeControls,
1153- nextArrow,
1154- nextArrowOff,
1155- QPixmap(),
1156- defaultAction);
1157+ nextArrow,
1158+ nextArrowOff,
1159+ QPixmap());
1160 nextTelescopeButton->setToolTip(q_("Next telescope"));
1161
1162 connect(nextOcularButton, SIGNAL(triggered()),
1163- ocularsPlugin, SLOT(incrementOcularIndex()));
1164+ ocularsPlugin, SLOT(incrementOcularIndex()));
1165 connect(nextCcdButton, SIGNAL(triggered()),
1166- ocularsPlugin, SLOT(incrementCCDIndex()));
1167+ ocularsPlugin, SLOT(incrementCCDIndex()));
1168 connect(nextTelescopeButton, SIGNAL(triggered()),
1169- ocularsPlugin, SLOT(incrementTelescopeIndex()));
1170+ ocularsPlugin, SLOT(incrementTelescopeIndex()));
1171 connect(prevOcularButton, SIGNAL(triggered()),
1172- ocularsPlugin, SLOT(decrementOcularIndex()));
1173+ ocularsPlugin, SLOT(decrementOcularIndex()));
1174 connect(prevCcdButton, SIGNAL(triggered()),
1175- ocularsPlugin, SLOT(decrementCCDIndex()));
1176+ ocularsPlugin, SLOT(decrementCCDIndex()));
1177 connect(prevTelescopeButton, SIGNAL(triggered()),
1178- ocularsPlugin, SLOT(decrementTelescopeIndex()));
1179+ ocularsPlugin, SLOT(decrementTelescopeIndex()));
1180 connect(nextLensButton, SIGNAL(triggered()),
1181- ocularsPlugin, SLOT(incrementLensIndex()));
1182+ ocularsPlugin, SLOT(incrementLensIndex()));
1183 connect(prevLensButton, SIGNAL(triggered()),
1184- ocularsPlugin, SLOT(decrementLensIndex()));
1185+ ocularsPlugin, SLOT(decrementLensIndex()));
1186
1187 QColor cOn(255, 255, 255);
1188 QColor cOff(102, 102, 102);
1189@@ -256,11 +239,11 @@
1190 QPixmap pOff = createPixmapFromText(degrees, degreesW, lineHeight, newFont, cOff);
1191 QPixmap pHover = createPixmapFromText(degrees, degreesW, lineHeight, newFont, cHover);
1192 rotateCcdMinus15Button = new StelButton(ccdControls,
1193- pOn,
1194- pOff,
1195- pHover,
1196- defaultAction,
1197- true);
1198+ pOn,
1199+ pOff,
1200+ pHover,
1201+ NULL,
1202+ true);
1203 rotateCcdMinus15Button->setToolTip(q_("Rotate the sensor frame 15 degrees counterclockwise"));
1204
1205 degrees = QString("-5%1").arg(QChar(0x00B0));
1206@@ -269,10 +252,10 @@
1207 pOff = createPixmapFromText(degrees, degreesW, lineHeight, newFont, cOff);
1208 pHover = createPixmapFromText(degrees, degreesW, lineHeight, newFont, cHover);
1209 rotateCcdMinus5Button = new StelButton(ccdControls,
1210- pOn,
1211- pOff,
1212- pHover,
1213- defaultAction,
1214+ pOn,
1215+ pOff,
1216+ pHover,
1217+ NULL,
1218 true);
1219 rotateCcdMinus5Button->setToolTip(q_("Rotate the sensor frame 5 degrees counterclockwise"));
1220
1221@@ -284,8 +267,8 @@
1222 rotateCcdMinus1Button = new StelButton(ccdControls,
1223 pOn,
1224 pOff,
1225- pHover,
1226- defaultAction,
1227+ pHover,
1228+ NULL,
1229 true);
1230 rotateCcdMinus1Button->setToolTip(q_("Rotate the sensor frame 1 degree counterclockwise"));
1231
1232@@ -295,10 +278,10 @@
1233 pOff = createPixmapFromText(degrees, degreesW, lineHeight, newFont, cOff);
1234 pHover = createPixmapFromText(degrees, degreesW, lineHeight, newFont, cHover);
1235 resetCcdRotationButton = new StelButton(ccdControls,
1236- pOn,
1237- pOff,
1238- pHover,
1239- defaultAction,
1240+ pOn,
1241+ pOff,
1242+ pHover,
1243+ NULL,
1244 true);
1245 resetCcdRotationButton->setToolTip(q_("Reset the sensor frame rotation"));
1246
1247@@ -311,7 +294,7 @@
1248 pOn,
1249 pOff,
1250 pHover,
1251- defaultAction,
1252+ NULL,
1253 true);
1254 rotateCcdPlus1Button->setToolTip(q_("Rotate the sensor frame 1 degree clockwise"));
1255
1256@@ -324,7 +307,7 @@
1257 pOn,
1258 pOff,
1259 pHover,
1260- defaultAction,
1261+ NULL,
1262 true);
1263 rotateCcdPlus5Button->setToolTip(q_("Rotate the sensor frame 5 degrees clockwise"));
1264
1265@@ -336,8 +319,8 @@
1266 rotateCcdPlus15Button = new StelButton(ccdControls,
1267 pOn,
1268 pOff,
1269- pHover,
1270- defaultAction,
1271+ pHover,
1272+ NULL,
1273 true);
1274 rotateCcdPlus15Button->setToolTip(q_("Rotate the sensor frame 15 degrees clockwise"));
1275
1276@@ -350,34 +333,34 @@
1277 sm->setMapping(rotateCcdPlus15Button, QString("15"));
1278
1279 connect(rotateCcdMinus15Button, SIGNAL(triggered()),
1280- sm, SLOT(map()));
1281+ sm, SLOT(map()));
1282 connect(rotateCcdMinus5Button, SIGNAL(triggered()),
1283- sm, SLOT(map()));
1284+ sm, SLOT(map()));
1285 connect(rotateCcdMinus1Button, SIGNAL(triggered()),
1286- sm, SLOT(map()));
1287+ sm, SLOT(map()));
1288 connect(rotateCcdPlus1Button, SIGNAL(triggered()),
1289- sm, SLOT(map()));
1290+ sm, SLOT(map()));
1291 connect(rotateCcdPlus5Button, SIGNAL(triggered()),
1292- sm, SLOT(map()));
1293+ sm, SLOT(map()));
1294 connect(rotateCcdPlus15Button, SIGNAL(triggered()),
1295- sm, SLOT(map()));
1296+ sm, SLOT(map()));
1297 connect(resetCcdRotationButton, SIGNAL(triggered()),
1298- ocularsPlugin, SLOT(ccdRotationReset()));
1299+ ocularsPlugin, SLOT(ccdRotationReset()));
1300
1301 connect(rotateCcdMinus15Button, SIGNAL(triggered()),
1302- this, SLOT(updateCcdControls()));
1303+ this, SLOT(updateCcdControls()));
1304 connect(rotateCcdMinus5Button, SIGNAL(triggered()),
1305- this, SLOT(updateCcdControls()));
1306+ this, SLOT(updateCcdControls()));
1307 connect(rotateCcdMinus1Button, SIGNAL(triggered()),
1308- this, SLOT(updateCcdControls()));
1309+ this, SLOT(updateCcdControls()));
1310 connect(rotateCcdPlus1Button, SIGNAL(triggered()),
1311- this, SLOT(updateCcdControls()));
1312+ this, SLOT(updateCcdControls()));
1313 connect(rotateCcdPlus5Button, SIGNAL(triggered()),
1314- this, SLOT(updateCcdControls()));
1315+ this, SLOT(updateCcdControls()));
1316 connect(rotateCcdPlus15Button, SIGNAL(triggered()),
1317- this, SLOT(updateCcdControls()));
1318+ this, SLOT(updateCcdControls()));
1319 connect(resetCcdRotationButton, SIGNAL(triggered()),
1320- this, SLOT(updateCcdControls()));
1321+ this, SLOT(updateCcdControls()));
1322
1323
1324 //Set the layout and update the size
1325@@ -395,7 +378,7 @@
1326
1327 //Border/background for the widget
1328 borderPath = new QGraphicsPathItem();
1329- borderPath->setZValue(100);
1330+ borderPath->setZValue(100);
1331 QBrush borderBrush(QColor::fromRgbF(0.22, 0.22, 0.23, 0.2));
1332 borderPath->setBrush(borderBrush);
1333 QPen borderPen = QPen(QColor::fromRgbF(0.7,0.7,0.7,0.5));
1334@@ -405,17 +388,17 @@
1335
1336 updatePosition();
1337 connect (parentWidget, SIGNAL(geometryChanged()),
1338- this, SLOT(updatePosition()));
1339+ this, SLOT(updatePosition()));
1340
1341 //Connecting other slots
1342 connect(ocularsPlugin, SIGNAL(selectedOcularChanged()),
1343- this, SLOT(updateOcularControls()));
1344+ this, SLOT(updateOcularControls()));
1345 connect(ocularsPlugin, SIGNAL(selectedCCDChanged()),
1346- this, SLOT(updateCcdControls()));
1347+ this, SLOT(updateCcdControls()));
1348 connect(ocularsPlugin, SIGNAL(selectedTelescopeChanged()),
1349- this, SLOT(updateTelescopeControls()));
1350+ this, SLOT(updateTelescopeControls()));
1351 connect(ocularsPlugin, SIGNAL(selectedLensChanged()),
1352- this, SLOT(updateTelescopeControls()));
1353+ this, SLOT(updateTelescopeControls()));
1354
1355 //Night mode
1356 connect(&stelApp, SIGNAL(colorSchemeChanged(const QString&)),
1357@@ -479,7 +462,7 @@
1358 QPointF verticalBorderStart = geometry().topLeft();
1359 QPointF horizontalBorderEnd = geometry().bottomRight();
1360 QPointF cornerArcStart(verticalBorderStart.x(),
1361- horizontalBorderEnd.y() - cornerRadius);
1362+ horizontalBorderEnd.y() - cornerRadius);
1363 newBorderPath.moveTo(verticalBorderStart);
1364 newBorderPath.lineTo(cornerArcStart);
1365 newBorderPath.arcTo(cornerArcStart.x(), cornerArcStart.y(), cornerRadius, cornerRadius, 180, 90);
1366@@ -552,7 +535,7 @@
1367 QString apparentFovString = QString::number(apparentFov);
1368 apparentFovString.append(QChar(0x00B0));// Degree sign
1369 QString apparentFovLabel = QString(q_("Ocular aFOV: %1"))
1370- .arg(apparentFovString);
1371+ .arg(apparentFovString);
1372 fieldOcularAfov->setPlainText(apparentFovLabel);
1373 fieldOcularAfov->setToolTip(q_("Apparent field of view of the ocular"));
1374 fieldOcularAfov->setPos(posX, posY);
1375@@ -637,8 +620,8 @@
1376
1377 //Get the name
1378 int index = ocularsPlugin->selectedCCDIndex;
1379- CCD* ccd = ocularsPlugin->ccds[index];
1380- Q_ASSERT(ccd);
1381+ CCD* ccd = ocularsPlugin->ccds[index];
1382+ Q_ASSERT(ccd);
1383 QString name = ccd->name();
1384 QString fullName;
1385 if (name.isEmpty())
1386@@ -801,7 +784,7 @@
1387 posY = 0.;
1388 widgetHeight = 0.;
1389
1390- fieldMagnification->setToolTip(q_("Magnification provided by these binoculars"));
1391+ fieldMagnification->setToolTip(q_("Magnification provided by these binoculars"));
1392 fieldFov->setToolTip(q_("Actual field of view provided by these binoculars"));
1393 fieldExitPupil->setToolTip(q_("Exit pupil provided by these binoculars"));
1394 }
1395@@ -811,15 +794,15 @@
1396 nextTelescopeButton->setVisible(true);
1397 fieldTelescopeName->setVisible(true);
1398
1399- fieldMagnification->setToolTip(q_("Magnification provided by this ocular/lens/telescope combination"));
1400+ fieldMagnification->setToolTip(q_("Magnification provided by this ocular/lens/telescope combination"));
1401 fieldFov->setToolTip(q_("Actual field of view provided by this ocular/lens/telescope combination"));
1402 fieldExitPupil->setToolTip(q_("Exit pupil provided by this ocular/lens/telescope combination"));
1403 }
1404
1405 //WTF? Rounding?
1406 double magnification = ((int)(ocular->magnification(telescope, lens) * 10.0)) / 10.0;
1407- QString magnificationString = QString::number(magnification);
1408- magnificationString.append(QChar(0x00D7));
1409+ QString magnificationString = QString::number(magnification);
1410+ magnificationString.append(QChar(0x00D7));
1411 QString magnificationLabel = QString(q_("Magnification: %1")).arg(magnificationString);
1412 fieldMagnification->setPlainText(magnificationLabel);
1413 fieldMagnification->setPos(posX, posY);
1414@@ -963,7 +946,7 @@
1415 void OcularsGuiPanel::updateMainButtonsPositions()
1416 {
1417 Q_ASSERT(buttonOcular);
1418- Q_ASSERT(buttonCrosshairs);
1419+ Q_ASSERT(buttonCrosshairs);
1420 Q_ASSERT(buttonCcd);
1421 Q_ASSERT(buttonTelrad);
1422 Q_ASSERT(buttonConfiguration);
1423@@ -984,7 +967,7 @@
1424 {
1425 qreal parentWidth = buttonOcular->parentItem()->boundingRect().width();
1426 int nGaps = n - 1;//n buttons have n-1 gaps
1427- spacing = qRound((parentWidth-width)/nGaps);
1428+ spacing = qRound((parentWidth-width)/nGaps);
1429 }
1430 buttonOcular->setPos(posX, posY);
1431 posX += buttonOcular->getButtonPixmapWidth() + spacing;
1432@@ -1067,11 +1050,11 @@
1433 }
1434
1435 QPixmap OcularsGuiPanel::createPixmapFromText(const QString& text,
1436- int width,
1437- int height,
1438- const QFont& font,
1439- const QColor& textColor,
1440- const QColor& backgroundColor)
1441+ int width,
1442+ int height,
1443+ const QFont& font,
1444+ const QColor& textColor,
1445+ const QColor& backgroundColor)
1446 {
1447 if (width <= 0 || height <=0) {
1448 return QPixmap();
1449@@ -1088,8 +1071,8 @@
1450 painter.setFont(font);
1451 painter.setPen(QPen(textColor));
1452 painter.drawText(0, 0, width, height,
1453- Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextSingleLine,
1454- text);
1455+ Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextSingleLine,
1456+ text);
1457
1458 return pixmap;
1459 }
1460
1461=== added directory 'plugins/RemoteControl'
1462=== added file 'plugins/RemoteControl/CMakeLists.txt'
1463--- plugins/RemoteControl/CMakeLists.txt 1970-01-01 00:00:00 +0000
1464+++ plugins/RemoteControl/CMakeLists.txt 2016-06-12 13:59:22 +0000
1465@@ -0,0 +1,46 @@
1466+# This is the cmake config file for the RemoteControl plugin
1467+SET(REMOTECONTROL_VERSION "0.0.1")
1468+ADD_DEFINITIONS(-DREMOTECONTROL_VERSION="${REMOTECONTROL_VERSION}")
1469+SET(REMOTECONTROL_WEBROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/webroot/")
1470+ADD_DEFINITIONS(-DREMOTECONTROL_WEBROOT_PATH="${REMOTECONTROL_WEBROOT_PATH}")
1471+
1472+ADD_SUBDIRECTORY( src )
1473+
1474+# Custom target for updating the translationdata.js
1475+find_package(PythonInterp)
1476+
1477+if(PYTHON_EXECUTABLE)
1478+ add_custom_target(RemoteControl-update-translationdata
1479+ COMMAND ${PYTHON_EXECUTABLE} util/update_translationdata.py
1480+ ${PROJECT_SOURCE_DIR}/po/stellarium-remotecontrol/stellarium-remotecontrol-js.pot ${REMOTECONTROL_WEBROOT_PATH}/js/translationdata.js
1481+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
1482+ COMMENT "Updating RemoteControl translation data"
1483+ VERBATIM
1484+ )
1485+
1486+ add_dependencies(RemoteControl-update-translationdata generate-pot-stellarium-remotecontrol-js)
1487+endif()
1488+
1489+IF(APPLE)
1490+ SET(CMAKE_INSTALL_PREFIX $ENV{HOME}/Library/Application\ Support/Stellarium)
1491+ElSE(APPLE)
1492+ SET(CMAKE_INSTALL_PREFIX $ENV{HOME}/.stellarium)
1493+ENDIF(APPLE)
1494+INSTALL(FILES DESTINATION "modules/RemoteControl")
1495+
1496+
1497+########### install files ###############
1498+# install webroot
1499+INSTALL(DIRECTORY ${REMOTECONTROL_WEBROOT_PATH} DESTINATION share/${PACKAGE}/webroot FILES_MATCHING
1500+ PATTERN "*.png"
1501+ PATTERN "*.gif"
1502+ PATTERN "*.html"
1503+ PATTERN "*.js"
1504+ PATTERN "*.css"
1505+ PATTERN "*.eot"
1506+ PATTERN "*.svg"
1507+ PATTERN "*.ttf"
1508+ PATTERN "*.woff"
1509+ PATTERN "*.woff2"
1510+ PATTERN "translate_files"
1511+ PATTERN "*.ico")
1512\ No newline at end of file
1513
1514=== added file 'plugins/RemoteControl/COPYING'
1515--- plugins/RemoteControl/COPYING 1970-01-01 00:00:00 +0000
1516+++ plugins/RemoteControl/COPYING 2016-06-12 13:59:22 +0000
1517@@ -0,0 +1,340 @@
1518+ GNU GENERAL PUBLIC LICENSE
1519+ Version 2, June 1991
1520+
1521+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
1522+ 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
1523+ Everyone is permitted to copy and distribute verbatim copies
1524+ of this license document, but changing it is not allowed.
1525+
1526+ Preamble
1527+
1528+ The licenses for most software are designed to take away your
1529+freedom to share and change it. By contrast, the GNU General Public
1530+License is intended to guarantee your freedom to share and change free
1531+software--to make sure the software is free for all its users. This
1532+General Public License applies to most of the Free Software
1533+Foundation's software and to any other program whose authors commit to
1534+using it. (Some other Free Software Foundation software is covered by
1535+the GNU Library General Public License instead.) You can apply it to
1536+your programs, too.
1537+
1538+ When we speak of free software, we are referring to freedom, not
1539+price. Our General Public Licenses are designed to make sure that you
1540+have the freedom to distribute copies of free software (and charge for
1541+this service if you wish), that you receive source code or can get it
1542+if you want it, that you can change the software or use pieces of it
1543+in new free programs; and that you know you can do these things.
1544+
1545+ To protect your rights, we need to make restrictions that forbid
1546+anyone to deny you these rights or to ask you to surrender the rights.
1547+These restrictions translate to certain responsibilities for you if you
1548+distribute copies of the software, or if you modify it.
1549+
1550+ For example, if you distribute copies of such a program, whether
1551+gratis or for a fee, you must give the recipients all the rights that
1552+you have. You must make sure that they, too, receive or can get the
1553+source code. And you must show them these terms so they know their
1554+rights.
1555+
1556+ We protect your rights with two steps: (1) copyright the software, and
1557+(2) offer you this license which gives you legal permission to copy,
1558+distribute and/or modify the software.
1559+
1560+ Also, for each author's protection and ours, we want to make certain
1561+that everyone understands that there is no warranty for this free
1562+software. If the software is modified by someone else and passed on, we
1563+want its recipients to know that what they have is not the original, so
1564+that any problems introduced by others will not reflect on the original
1565+authors' reputations.
1566+
1567+ Finally, any free program is threatened constantly by software
1568+patents. We wish to avoid the danger that redistributors of a free
1569+program will individually obtain patent licenses, in effect making the
1570+program proprietary. To prevent this, we have made it clear that any
1571+patent must be licensed for everyone's free use or not licensed at all.
1572+
1573+ The precise terms and conditions for copying, distribution and
1574+modification follow.
1575+
1576
1577+ GNU GENERAL PUBLIC LICENSE
1578+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
1579+
1580+ 0. This License applies to any program or other work which contains
1581+a notice placed by the copyright holder saying it may be distributed
1582+under the terms of this General Public License. The "Program", below,
1583+refers to any such program or work, and a "work based on the Program"
1584+means either the Program or any derivative work under copyright law:
1585+that is to say, a work containing the Program or a portion of it,
1586+either verbatim or with modifications and/or translated into another
1587+language. (Hereinafter, translation is included without limitation in
1588+the term "modification".) Each licensee is addressed as "you".
1589+
1590+Activities other than copying, distribution and modification are not
1591+covered by this License; they are outside its scope. The act of
1592+running the Program is not restricted, and the output from the Program
1593+is covered only if its contents constitute a work based on the
1594+Program (independent of having been made by running the Program).
1595+Whether that is true depends on what the Program does.
1596+
1597+ 1. You may copy and distribute verbatim copies of the Program's
1598+source code as you receive it, in any medium, provided that you
1599+conspicuously and appropriately publish on each copy an appropriate
1600+copyright notice and disclaimer of warranty; keep intact all the
1601+notices that refer to this License and to the absence of any warranty;
1602+and give any other recipients of the Program a copy of this License
1603+along with the Program.
1604+
1605+You may charge a fee for the physical act of transferring a copy, and
1606+you may at your option offer warranty protection in exchange for a fee.
1607+
1608+ 2. You may modify your copy or copies of the Program or any portion
1609+of it, thus forming a work based on the Program, and copy and
1610+distribute such modifications or work under the terms of Section 1
1611+above, provided that you also meet all of these conditions:
1612+
1613+ a) You must cause the modified files to carry prominent notices
1614+ stating that you changed the files and the date of any change.
1615+
1616+ b) You must cause any work that you distribute or publish, that in
1617+ whole or in part contains or is derived from the Program or any
1618+ part thereof, to be licensed as a whole at no charge to all third
1619+ parties under the terms of this License.
1620+
1621+ c) If the modified program normally reads commands interactively
1622+ when run, you must cause it, when started running for such
1623+ interactive use in the most ordinary way, to print or display an
1624+ announcement including an appropriate copyright notice and a
1625+ notice that there is no warranty (or else, saying that you provide
1626+ a warranty) and that users may redistribute the program under
1627+ these conditions, and telling the user how to view a copy of this
1628+ License. (Exception: if the Program itself is interactive but
1629+ does not normally print such an announcement, your work based on
1630+ the Program is not required to print an announcement.)
1631+
1632
1633+These requirements apply to the modified work as a whole. If
1634+identifiable sections of that work are not derived from the Program,
1635+and can be reasonably considered independent and separate works in
1636+themselves, then this License, and its terms, do not apply to those
1637+sections when you distribute them as separate works. But when you
1638+distribute the same sections as part of a whole which is a work based
1639+on the Program, the distribution of the whole must be on the terms of
1640+this License, whose permissions for other licensees extend to the
1641+entire whole, and thus to each and every part regardless of who wrote it.
1642+
1643+Thus, it is not the intent of this section to claim rights or contest
1644+your rights to work written entirely by you; rather, the intent is to
1645+exercise the right to control the distribution of derivative or
1646+collective works based on the Program.
1647+
1648+In addition, mere aggregation of another work not based on the Program
1649+with the Program (or with a work based on the Program) on a volume of
1650+a storage or distribution medium does not bring the other work under
1651+the scope of this License.
1652+
1653+ 3. You may copy and distribute the Program (or a work based on it,
1654+under Section 2) in object code or executable form under the terms of
1655+Sections 1 and 2 above provided that you also do one of the following:
1656+
1657+ a) Accompany it with the complete corresponding machine-readable
1658+ source code, which must be distributed under the terms of Sections
1659+ 1 and 2 above on a medium customarily used for software interchange; or,
1660+
1661+ b) Accompany it with a written offer, valid for at least three
1662+ years, to give any third party, for a charge no more than your
1663+ cost of physically performing source distribution, a complete
1664+ machine-readable copy of the corresponding source code, to be
1665+ distributed under the terms of Sections 1 and 2 above on a medium
1666+ customarily used for software interchange; or,
1667+
1668+ c) Accompany it with the information you received as to the offer
1669+ to distribute corresponding source code. (This alternative is
1670+ allowed only for noncommercial distribution and only if you
1671+ received the program in object code or executable form with such
1672+ an offer, in accord with Subsection b above.)
1673+
1674+The source code for a work means the preferred form of the work for
1675+making modifications to it. For an executable work, complete source
1676+code means all the source code for all modules it contains, plus any
1677+associated interface definition files, plus the scripts used to
1678+control compilation and installation of the executable. However, as a
1679+special exception, the source code distributed need not include
1680+anything that is normally distributed (in either source or binary
1681+form) with the major components (compiler, kernel, and so on) of the
1682+operating system on which the executable runs, unless that component
1683+itself accompanies the executable.
1684+
1685+If distribution of executable or object code is made by offering
1686+access to copy from a designated place, then offering equivalent
1687+access to copy the source code from the same place counts as
1688+distribution of the source code, even though third parties are not
1689+compelled to copy the source along with the object code.
1690+
1691
1692+ 4. You may not copy, modify, sublicense, or distribute the Program
1693+except as expressly provided under this License. Any attempt
1694+otherwise to copy, modify, sublicense or distribute the Program is
1695+void, and will automatically terminate your rights under this License.
1696+However, parties who have received copies, or rights, from you under
1697+this License will not have their licenses terminated so long as such
1698+parties remain in full compliance.
1699+
1700+ 5. You are not required to accept this License, since you have not
1701+signed it. However, nothing else grants you permission to modify or
1702+distribute the Program or its derivative works. These actions are
1703+prohibited by law if you do not accept this License. Therefore, by
1704+modifying or distributing the Program (or any work based on the
1705+Program), you indicate your acceptance of this License to do so, and
1706+all its terms and conditions for copying, distributing or modifying
1707+the Program or works based on it.
1708+
1709+ 6. Each time you redistribute the Program (or any work based on the
1710+Program), the recipient automatically receives a license from the
1711+original licensor to copy, distribute or modify the Program subject to
1712+these terms and conditions. You may not impose any further
1713+restrictions on the recipients' exercise of the rights granted herein.
1714+You are not responsible for enforcing compliance by third parties to
1715+this License.
1716+
1717+ 7. If, as a consequence of a court judgment or allegation of patent
1718+infringement or for any other reason (not limited to patent issues),
1719+conditions are imposed on you (whether by court order, agreement or
1720+otherwise) that contradict the conditions of this License, they do not
1721+excuse you from the conditions of this License. If you cannot
1722+distribute so as to satisfy simultaneously your obligations under this
1723+License and any other pertinent obligations, then as a consequence you
1724+may not distribute the Program at all. For example, if a patent
1725+license would not permit royalty-free redistribution of the Program by
1726+all those who receive copies directly or indirectly through you, then
1727+the only way you could satisfy both it and this License would be to
1728+refrain entirely from distribution of the Program.
1729+
1730+If any portion of this section is held invalid or unenforceable under
1731+any particular circumstance, the balance of the section is intended to
1732+apply and the section as a whole is intended to apply in other
1733+circumstances.
1734+
1735+It is not the purpose of this section to induce you to infringe any
1736+patents or other property right claims or to contest validity of any
1737+such claims; this section has the sole purpose of protecting the
1738+integrity of the free software distribution system, which is
1739+implemented by public license practices. Many people have made
1740+generous contributions to the wide range of software distributed
1741+through that system in reliance on consistent application of that
1742+system; it is up to the author/donor to decide if he or she is willing
1743+to distribute software through any other system and a licensee cannot
1744+impose that choice.
1745+
1746+This section is intended to make thoroughly clear what is believed to
1747+be a consequence of the rest of this License.
1748+
1749
1750+ 8. If the distribution and/or use of the Program is restricted in
1751+certain countries either by patents or by copyrighted interfaces, the
1752+original copyright holder who places the Program under this License
1753+may add an explicit geographical distribution limitation excluding
1754+those countries, so that distribution is permitted only in or among
1755+countries not thus excluded. In such case, this License incorporates
1756+the limitation as if written in the body of this License.
1757+
1758+ 9. The Free Software Foundation may publish revised and/or new versions
1759+of the General Public License from time to time. Such new versions will
1760+be similar in spirit to the present version, but may differ in detail to
1761+address new problems or concerns.
1762+
1763+Each version is given a distinguishing version number. If the Program
1764+specifies a version number of this License which applies to it and "any
1765+later version", you have the option of following the terms and conditions
1766+either of that version or of any later version published by the Free
1767+Software Foundation. If the Program does not specify a version number of
1768+this License, you may choose any version ever published by the Free Software
1769+Foundation.
1770+
1771+ 10. If you wish to incorporate parts of the Program into other free
1772+programs whose distribution conditions are different, write to the author
1773+to ask for permission. For software which is copyrighted by the Free
1774+Software Foundation, write to the Free Software Foundation; we sometimes
1775+make exceptions for this. Our decision will be guided by the two goals
1776+of preserving the free status of all derivatives of our free software and
1777+of promoting the sharing and reuse of software generally.
1778+
1779+ NO WARRANTY
1780+
1781+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
1782+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
1783+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
1784+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
1785+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
1786+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
1787+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
1788+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
1789+REPAIR OR CORRECTION.
1790+
1791+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
1792+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
1793+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
1794+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
1795+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
1796+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
1797+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
1798+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
1799+POSSIBILITY OF SUCH DAMAGES.
1800+
1801+ END OF TERMS AND CONDITIONS
1802+
1803
1804+ How to Apply These Terms to Your New Programs
1805+
1806+ If you develop a new program, and you want it to be of the greatest
1807+possible use to the public, the best way to achieve this is to make it
1808+free software which everyone can redistribute and change under these terms.
1809+
1810+ To do so, attach the following notices to the program. It is safest
1811+to attach them to the start of each source file to most effectively
1812+convey the exclusion of warranty; and each file should have at least
1813+the "copyright" line and a pointer to where the full notice is found.
1814+
1815+ <one line to give the program's name and a brief idea of what it does.>
1816+ Copyright (C) <year> <name of author>
1817+
1818+ This program is free software; you can redistribute it and/or modify
1819+ it under the terms of the GNU General Public License as published by
1820+ the Free Software Foundation; either version 2 of the License, or
1821+ (at your option) any later version.
1822+
1823+ This program is distributed in the hope that it will be useful,
1824+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1825+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1826+ GNU General Public License for more details.
1827+
1828+ You should have received a copy of the GNU General Public License
1829+ along with this program; if not, write to the Free Software
1830+ Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
1831+
1832+
1833+Also add information on how to contact you by electronic and paper mail.
1834+
1835+If the program is interactive, make it output a short notice like this
1836+when it starts in an interactive mode:
1837+
1838+ Gnomovision version 69, Copyright (C) year name of author
1839+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
1840+ This is free software, and you are welcome to redistribute it
1841+ under certain conditions; type `show c' for details.
1842+
1843+The hypothetical commands `show w' and `show c' should show the appropriate
1844+parts of the General Public License. Of course, the commands you use may
1845+be called something other than `show w' and `show c'; they could even be
1846+mouse-clicks or menu items--whatever suits your program.
1847+
1848+You should also get your employer (if you work as a programmer) or your
1849+school, if any, to sign a "copyright disclaimer" for the program, if
1850+necessary. Here is a sample; alter the names:
1851+
1852+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
1853+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
1854+
1855+ <signature of Ty Coon>, 1 April 1989
1856+ Ty Coon, President of Vice
1857+
1858+This General Public License does not permit incorporating your program into
1859+proprietary programs. If your program is a subroutine library, you may
1860+consider it more useful to permit linking proprietary applications with the
1861+library. If this is what you want to do, use the GNU Library General
1862+Public License instead of this License.
1863
1864=== added file 'plugins/RemoteControl/RemoteControl.qrc'
1865--- plugins/RemoteControl/RemoteControl.qrc 1970-01-01 00:00:00 +0000
1866+++ plugins/RemoteControl/RemoteControl.qrc 2016-06-12 13:59:22 +0000
1867@@ -0,0 +1,6 @@
1868+<RCC>
1869+ <qresource prefix="/RemoteControl">
1870+ <file>resources/bt_remote_off.png</file>
1871+ <file>resources/bt_remote_on.png</file>
1872+ </qresource>
1873+</RCC>
1874
1875=== added directory 'plugins/RemoteControl/doc'
1876=== added file 'plugins/RemoteControl/doc/qtwebapp.doxygen'
1877--- plugins/RemoteControl/doc/qtwebapp.doxygen 1970-01-01 00:00:00 +0000
1878+++ plugins/RemoteControl/doc/qtwebapp.doxygen 2016-06-12 13:59:22 +0000
1879@@ -0,0 +1,35 @@
1880+/*
1881+ * Stellarium
1882+ * Copyright (C) 2016 Florian Schaukowitsch
1883+ *
1884+ * This program is free software; you can redistribute it and/or
1885+ * modify it under the terms of the GNU General Public License
1886+ * as published by the Free Software Foundation; either version 2
1887+ * of the License, or (at your option) any later version.
1888+ *
1889+ * This program is distributed in the hope that it will be useful,
1890+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1891+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1892+ * GNU General Public License for more details.
1893+ *
1894+ * You should have received a copy of the GNU General Public License
1895+ * along with this program; if not, write to the Free Software
1896+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1897+ */
1898+
1899+/*!
1900+
1901+@defgroup qtWebApp QtWebApp library
1902+
1903+The QtWebApp library is developed by Stefan Frings (http://stefanfrings.de/qtwebapp/index-en.html).
1904+It is used by the Stellarium \ref remoteControl to provide the HTTP server that serves the plugin's API.
1905+
1906+Some changes have been made to the library to fit it better into Stellarium. The main differences are:
1907+- The settings are no longer specified using QSettings, but with configuration structs (HttpListenerSettings, StaticFileControllerSettings, etc)
1908+- The template engine supports translating strings at runtime through tags in pseudo-PHP style instead of just different files per language (ITemplateTranslationProvider, Template::translate)
1909+- The Content-Type detection of the StaticFileController has been extended to use QMimeDatabase, if required.
1910+
1911+@author Stefan Frings, Florian Schaukowitsch
1912+@copyright GNU Lesser General Public License (https://www.gnu.org/licenses/lgpl.html)
1913+
1914+*/
1915
1916=== added file 'plugins/RemoteControl/doc/remoteControl.doxygen'
1917--- plugins/RemoteControl/doc/remoteControl.doxygen 1970-01-01 00:00:00 +0000
1918+++ plugins/RemoteControl/doc/remoteControl.doxygen 2016-06-12 13:59:22 +0000
1919@@ -0,0 +1,61 @@
1920+/*
1921+ * Stellarium
1922+ * Copyright (C) 2016 Florian Schaukowitsch
1923+ *
1924+ * This program is free software; you can redistribute it and/or
1925+ * modify it under the terms of the GNU General Public License
1926+ * as published by the Free Software Foundation; either version 2
1927+ * of the License, or (at your option) any later version.
1928+ *
1929+ * This program is distributed in the hope that it will be useful,
1930+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1931+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1932+ * GNU General Public License for more details.
1933+ *
1934+ * You should have received a copy of the GNU General Public License
1935+ * along with this program; if not, write to the Free Software
1936+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1937+ */
1938+
1939+/*!
1940+@defgroup remoteControl Remote Control Plug-in
1941+@brief Control Stellarium through your web browser! For more information, see @ref remoteControlDoc.
1942+
1943+@page remoteControlDoc Remote Control Plug-in documentation
1944+The %RemoteControl plugin provides a remote control using a webserver interface, usable for single or even synchronized cluster of clients (via the RemoteSync plugin).
1945+You can simply connect via web browser to a
1946+configurable port (default: 8090) of your computer. To use it locally, you can use
1947+http://localhost:8090[/index.html]
1948+or for a slightly modified GUI which may be better suited for smaller 7inch screens, try
1949+http://localhost:8090/tablet7in.html.
1950+Your web browser has to support JavaScript and HTML5 (recommended in 2016: <a href="https://mozilla.org/firefox">Firefox</a>, <a href="https://www.google.com/chrome/">Chrome</a>).
1951+
1952+The web data for the interface resides in the <tt>/data/webroot</tt> directory inside the installation directory (<tt>share/stellarium/data/webroot</tt> on Linux), and can be customized with
1953+some knowledge of HTML, CSS and maybe JavaScript (not necessary for basic functionality, only when more complex additions are required).
1954+Alternative or derived HTML control GUIs must be placed into the same folder,
1955+the web server for now cannot read data from the private Stellarium user directory (<tt>~/.stellarium</tt>, <tt>\%APPDATA\%\\stellarium</tt>).
1956+
1957+This plugin makes extensive use of the StelProperty system introduced with it. This allows not only to trigger actions,
1958+but also set QVariant values, which is enough to control many things in the program.
1959+A few dedicated modules have been implemented closely following the existing GUI for view motion, location setting,
1960+landscape and skyculture selection, searching objects, etc.
1961+It is also possible to define interfaces that control plugins, and dynamically show them only when the plugin is enabled.
1962+
1963+Because the API is based on simple HTTP calls, it can also be called from command-line clients. For example,
1964+to execute the script "double_stars.ssc", one could use one of the following lines:
1965+@code
1966+wget -q --post-data 'id=double_stars.ssc' http://localhost:8090/api/scripts/run >/dev/null 2>&amp;1
1967+curl --data 'id=double_stars.ssc' http://localhost:8090/api/scripts/run >/dev/null 2>&amp;1
1968+curl -d 'id=double_stars.ssc' http://localhost:8090/api/scripts/run >/dev/null 2>&amp;1
1969+@endcode
1970+This allows triggering automatic show setups for museums etc.
1971+
1972+The entry point of the plugin is the RemoteControl class.
1973+- To see how the HTTP API looks like (i.e. if you want to extend it or access it without using the web interface), see @subpage remoteControlApi.
1974+- To see how the web interface works (i.e. if you want to modify it or add new controls), see @subpage remoteControlWeb.
1975+
1976+@author Florian Schaukowitsch, Georg Zotti
1977+@note This plugin includes parts of the \ref qtWebApp by Stefan Frings, used under the LGPL
1978+@note This plugin has been developed as project of ESA SoCiS 2015 (http://sophia.estec.esa.int/socis/)
1979+
1980+*/
1981
1982=== added file 'plugins/RemoteControl/doc/remoteControlApi.doxygen'
1983--- plugins/RemoteControl/doc/remoteControlApi.doxygen 1970-01-01 00:00:00 +0000
1984+++ plugins/RemoteControl/doc/remoteControlApi.doxygen 2016-06-12 13:59:22 +0000
1985@@ -0,0 +1,461 @@
1986+/*
1987+ * Stellarium
1988+ * Copyright (C) 2016 Florian Schaukowitsch
1989+ *
1990+ * This program is free software; you can redistribute it and/or
1991+ * modify it under the terms of the GNU General Public License
1992+ * as published by the Free Software Foundation; either version 2
1993+ * of the License, or (at your option) any later version.
1994+ *
1995+ * This program is distributed in the hope that it will be useful,
1996+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1997+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1998+ * GNU General Public License for more details.
1999+ *
2000+ * You should have received a copy of the GNU General Public License
2001+ * along with this program; if not, write to the Free Software
2002+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2003+ */
2004+
2005+/*!
2006+
2007+\page remoteControlApi %RemoteControl plugin HTTP API description
2008+
2009+The \ref remoteControl "RemoteControl plugin" provides an HTTP-based interface to Stellarium, implemented on the server-side through implementations of AbstractAPIService.
2010+The APIController maintains the list of registered services, and dispatches HTTP requests to the right service.
2011+The API is accessible under the server path `/api/`. For example, if you have the server running on the default port of 8090,
2012+you can access the operation \ref rcObjectServiceFind of the ObjectService to look for objects with \c moon in their name by accessing
2013+\code
2014+http://localhost:8090/api/objects/find?str=moon
2015+|____________________|___|_______|____|_______|
2016+ | | | | |------ Standard HTTP query string for parameters (key=value)
2017+ | | | |------------ find operation (defined by service)
2018+ | | |------------------- service (e.g. ObjectService)
2019+ | |------------------------- API prefix (always /api/)
2020+ |-------------------------------------- server access (http://host:port)
2021+\endcode
2022+
2023+Instead of the \ref remoteControlWeb "HTTP remote interface" you can also use tools like <a href="https://curl.haxx.se/">cURL</a>
2024+to access the API remotely. For POST operations, you would use the flag \c -d to pass parameters. For GET operations, you should use
2025+the additional flag \c -G if parameters are required. Examples:
2026+@code{.sh}
2027+# retrieve info about the script "double_stars.ssc" with a GET request
2028+curl -G -d 'id=double_stars.ssc' http://localhost:8090/api/scripts/info
2029+# run the script "double_stars.ssc" with a POST request
2030+curl -d 'id=double_stars.ssc' http://localhost:8090/api/scripts/run
2031+@endcode
2032+
2033+If authentication is enabled (see RemoteControl class), <a href="https://en.wikipedia.org/wiki/Basic_access_authentication">HTTP Basic access authentication</a> is expected, with an empty username.
2034+HTTPS configuration is currently not implemented, even if the underlying \ref qtWebApp would allow it.
2035+
2036+Most operations return data in the <a href="http://www.json.org/">JSON</a> format, allowing it to be easily used in web applications.
2037+The format of the returned JSON data is described for each operation below.
2038+Some operations return plain text if only simple data is requested, or to confirm the success of an operation:
2039+to indicate success "ok" may be returned, in an error case an HTTP error code may be returned together with a string "error: error message" in the response body.
2040+Other operations may return HTML or even image data, you can check the returned Content-Type header if you are not sure what to expect.
2041+
2042+\tableofcontents
2043+
2044+\section rcExtendApi Extending the API
2045+
2046+The simplest way to expose new data through the API is by using the StelProperty system for a property you want to access.
2047+In this way, the data is available through the MainService (allowing tracking of changes) and the StelPropertyService (giving a snapshot of current values, metadata information and allowing to change values).
2048+You do not need to change/implement a new service in any way for this case.
2049+
2050+If you want to expose more complex behaviour, you may need to implement your own AbstractAPIService and register it with the APIController.
2051+\todo Find out how to do this in plugin code
2052+
2053+\section rcApiReference API reference
2054+
2055+The default services are registered in the RequestHandler::RequestHandler() constructor. They are:
2056+
2057+Service | Path | Description
2058+--------------------- | --------------------------------------------------- | ------------------------
2059+MainService | \ref rcMainService "main" | \copybrief MainService
2060+ObjectService | \ref rcObjectService "objects" | \copybrief ObjectService
2061+ScriptService | \ref rcScriptService "scripts" | \copybrief ScriptService
2062+SimbadService | \ref rcSimbadService "simbad" | \copybrief SimbadService
2063+StelActionService | \ref rcStelActionService "stelaction" | \copybrief StelActionService
2064+StelPropertyService | \ref rcStelPropertyService "stelproperty" | \copybrief StelPropertyService
2065+LocationService | \ref rcLocationService "location" | \copybrief LocationService
2066+LocationSearchService | \ref rcLocationSearchService "locationsearch" | \copybrief LocationSearchService
2067+ViewService | \ref rcViewService "view" | \copybrief ViewService
2068+
2069+\subsection rcMainService MainService operations (/api/main/)
2070+\subsubsection rcMainServiceGET GET operations
2071+Implemented by MainService::getImpl
2072+
2073+\paragraph rcMainServiceStatus status
2074+Parameters: <tt>[actionId (Number)] [propId (Number)]</tt>\n
2075+This operation can be polled every few moments to find out if some primary Stellarium state changed. It returns a JSON object with the following format:
2076+\code{.js}
2077+{
2078+ //current location information, see StelLocation
2079+ location : {
2080+ name,
2081+ role,
2082+ planet,
2083+ latitude,
2084+ longitude,
2085+ altitude,
2086+ country,
2087+ state,
2088+ landscapeKey
2089+ },
2090+ //current time information
2091+ time : {
2092+ jday, //current Julian day
2093+ deltaT, //current deltaT as determined by the current dT algorithm
2094+ gmtShift, //the timezone shift to GMT
2095+ timeZone, //the timezone name
2096+ utc, //the time in UTC time zone as ISO8601 time string
2097+ local, //the time in local time zone as ISO8601 time string
2098+ isTimeNow, //if true, the Stellarium time equals the current real-world time
2099+ timerate //the current time rate (in secs)
2100+ },
2101+ selectioninfo, //string that contains the information of the currently selected object, as returned by StelObject::getInfoString
2102+ view : {
2103+ fov //current FOV
2104+ },
2105+
2106+ //the following is only inserted if an actionId parameter was given
2107+ //see below for more info
2108+ actionChanges : {
2109+ id, //currently valid action id, the interface should update its own id to this value
2110+ changes : {
2111+ //a list of boolean actions that changed since the actionId parameter
2112+ <actionName> : <actionValue>
2113+ }
2114+ },
2115+ //the following is only inserted if an propId parameter was given
2116+ //see below for more info
2117+ propertyChanges : {
2118+ id, //currently valid prop id, the interface should update its own id to this value
2119+ changes : {
2120+ //a list of properties that changed since the propId parameter
2121+ <propName> : <propValue>
2122+ }
2123+ }
2124+}
2125+\endcode
2126+
2127+The \c actionChanges and \c propertyChanges sections allow a remote interface to track boolean StelAction and/or StelProperty changes.
2128+On the initial poll, you should pass -2 as \p propId and \p actionId. This indicates to the service that you want a full
2129+list of properties/actions and their current values. When receiving the answer, you should set your local \p propId /\p actionId to the id
2130+contained in \c actionChanges and \c propertyChanges, and re-send it with the next request as parameter again.
2131+This allows the MainService to find out which changes must be sent to you (it maintains a queue of action/property changes internally, incrementing
2132+the ID with each change), and you only have to process the differences instead of everything.
2133+
2134+\paragraph rcMainServicePlugins plugins
2135+Returns the list of all known plugins, as a JSON object of format:
2136+\code{.js}
2137+{
2138+ //list of known plugins, in format:
2139+ <pluginName> : {
2140+ loadAtStartup, //if to load the plugin at startup
2141+ loaded, //if the plugin is currently loaded
2142+ //corresponds to the StelPluginInfo of the plugin
2143+ info : {
2144+ authors,
2145+ contact,
2146+ description,
2147+ displayedName,
2148+ startByDefault,
2149+ version
2150+ }
2151+ }
2152+}
2153+\endcode
2154+
2155+\subsubsection rcMainServicePOST POST operations
2156+Implemented by MainService::postImpl
2157+
2158+\paragraph rcMainServiceTime time
2159+Parameters: <tt>time (Number) timerate (Number)</tt>\n
2160+Sets the current Stellarium simulation time and/or timerate. The \p time parameter defines the current time (Julian day) as passed to StelCore::setJD.
2161+The \p timerate parameter allows to change the speed at which the simulation time moves (in JDay/sec) as passed to StelCore::setTimeRate.
2162+
2163+\paragraph rcMainServiceFocus focus
2164+Parameters: <tt>[target (String) | position (JSON Number Array of size 3, i.e. Vec3d)]</tt>\n
2165+Sets the current app focus/selection. If no parameters are given, the current selection is cleared.
2166+If the \p target parameter was given, the object to be selected is looked up by name (first the localized name is tried, then the english name).
2167+If the \p position parameter is used, it is interpreted as a coordinate in the J2000 frame, and focused using StelMovementMgr::moveToJ2000
2168+
2169+\paragraph rcMainServiceMove move
2170+Parameters: <tt>x (Number) y (Number)</tt>\n
2171+Allows viewport movement, like using the arrow keys in the main program. This allows interfaces to create a "virtual joystick" to move the view manually.
2172+This operation defines the intended move direction. \p x and \p y define the intended
2173+move speed in azimuth and altitude (i.e. a negative \p x means left). Values of +-1.0 correspond to the same speed as used for the arrow keys.
2174+This operation works in conjunction with the update() method - until the movement is stopped
2175+(i.e. \p x and \p y are zero), or no \c move command has been received for a specified time (about a second), the movement is performed in the given directions.
2176+
2177+\paragraph rcMainServiceFov fov
2178+Parameters: <tt>fov (Number)</tt>\n
2179+Sets the current field-of-view using StelCore::setFov
2180+
2181+\subsection rcObjectService ObjectService operations (/api/objects/)
2182+\subsubsection rcObjectServiceGET GET operations
2183+Implemented by ObjectService::getImpl
2184+
2185+\paragraph rcObjectServiceFind find
2186+Parameters: <tt>str (String)</tt>\n
2187+Finds objects which match the search string \p str, which may contain greek/unicode characters like in the SearchDialog.
2188+Returns a JSON String array of search matches
2189+
2190+\paragraph rcObjectServiceInfo info
2191+Parameters: <tt>[name (String)]</tt>\n
2192+Returns a HTML info string (StelObject::getInfoString) about the object identified by \p name.
2193+If no parameter is given, the currently selected object is used.
2194+
2195+\paragraph rcObjectServiceListobjecttypes listobjecttypes
2196+Returns all object types available in the internal catalogs as a JSON array of objects of format
2197+@code{.js}
2198+{
2199+ key, //the internal key for the object type
2200+ name, //the english name of the type
2201+ name_i18n //the type name in the current language
2202+}
2203+@endcode
2204+
2205+\paragraph rcObjectServiceListobjectsbytype listobjectsbytype
2206+Parameters: <tt>type (String) [english (Number)]</tt>\n
2207+Returns all objects of the specified \p type. If \p english is given and it evaluates to a "true" value, the english names
2208+will be returned, otherwise the localized names will be returned. Returns a JSON string array.
2209+
2210+\subsection rcScriptService ScriptService operations (/api/scripts/)
2211+\subsubsection rcScriptServiceGET GET operations
2212+Implemented by ScriptService::getImpl
2213+
2214+\paragraph rcScriptServiceList list
2215+Lists all known script files, as a JSON string array.
2216+
2217+\paragraph rcScriptServiceInfo info
2218+Parameters: <tt>id (String) [html (any type)] </tt>\n
2219+Returns information about the script identified by \p id.
2220+If the optional parameter \p html is present (its value is ignored),
2221+the info is formatted using StelScriptMgr::getHtmlDescription and
2222+suitable for inclusion into an \c iframe element,
2223+otherwise this operation returns a JSON object of format:
2224+@code{.js}
2225+{
2226+ id, //the script ID
2227+ name, //the english name of the script
2228+ name_localized, //the localized name of the script
2229+ description, //the english description of the script
2230+ description_localized, //the localized description of the script
2231+ author, //the author(s) of the script
2232+ license //the license of the script
2233+}
2234+@endcode
2235+
2236+\paragraph rcScriptServiceStatus status
2237+Returns the current script status as a JSON object of format:
2238+@code{.js}
2239+{
2240+ scriptIsRunning, //true if a script is running
2241+ runningScriptId //the currently running script ID
2242+}
2243+@endcode
2244+@note The StelScriptMgr also provides a StelProperty \c StelScriptMgr.runningScriptId that
2245+can be used to find out the active script.
2246+
2247+\subsubsection rcScriptServicePOST POST operations
2248+Implemented by ScriptService::postImpl
2249+
2250+\paragraph rcScriptServiceRun run
2251+Parameters: <tt>id (String)</tt>\n
2252+Runs the script with the given \p id. Will fail if a script is currently running.
2253+
2254+\paragraph rcScriptServiceDirect direct
2255+Parameters: <tt>code (String) [useIncludes (Bool)]</tt>\n
2256+Directly executes the given script \p code. If \p useIncludes is given and evaluates to true, the standard
2257+include folder will be used. Script execution will fail if a script is already running.
2258+
2259+\paragraph rcScriptServiceStop stop
2260+Stops the execution of a running script.
2261+
2262+\subsection rcSimbadService SimbadService operations (/api/simbad/)
2263+\subsubsection rcSimbadServiceGET GET operations
2264+Implemented by SimbadService::getImpl
2265+
2266+\paragraph rcSimbadServiceLookup lookup
2267+Parameters: <tt>str (String)</tt>\n
2268+Performs a SIMBAD lookup for the string \p str using the Stellarium-configured server and returns the results as a JSON object of format
2269+@code{.js}
2270+{
2271+ status, //the status of the lookup: either "empty" when nothing was found, "found" when at least 1 result was returned, and "error" if the lookup caused an error
2272+ status_i18n, //a localized status message for display
2273+ errorString, //if the status is "error", this contains more information about it
2274+ results: {
2275+ names : [
2276+ //an array of object names
2277+ ],
2278+ positions : [
2279+ //an array of object positions (i.e. first one corresponds to first name, etc.)
2280+ //format is an array of 3 numbers for each entry, i.e.:
2281+ [1,2,3],...
2282+ ]
2283+ }
2284+}
2285+@endcode
2286+
2287+\subsection rcStelActionService StelAction operations (/api/stelaction/)
2288+\subsubsection rcStelActionServiceGET GET operations
2289+Implemented by StelActionService::getImpl
2290+
2291+\paragraph rcStelActionServiceList list
2292+Lists all registered StelActions, in the format
2293+@code{.js}
2294+{
2295+ //translated StelAction group name
2296+ <groupName> : [
2297+ //all StelActions in the group <groupName>
2298+ <actionName> : {
2299+ id, //the ID of the action
2300+ isCheckable, //true if the action represents a boolean value
2301+ isChecked, //if "isCheckable" is true, shows the current boolean state
2302+ text //the translated description of the action
2303+ }
2304+ ]
2305+}
2306+@endcode
2307+
2308+\subsubsection rcStelActionServicePOST POST operations
2309+Implemented by StelActionService::postImpl
2310+
2311+\paragraph rcStelActionServiceDo do
2312+Parameters: <tt>id (String)</tt>\n
2313+Triggers or toggles the StelAction specified by \p id. If it was a boolean action, returns the new state of the action (strings "true"/"false").
2314+
2315+\subsection rcStelPropertyService StelProperty operations (/api/stelproperty/)
2316+\subsubsection rcStelPropertyServiceGET GET operations
2317+Implemented by StelPropertyService::getImpl
2318+
2319+\paragraph rcStelPropertyServiceList list
2320+Lists all registered StelProperties, in the format
2321+@code{.js}
2322+{
2323+ <propId> : {
2324+ value, //the current value of the StelProperty
2325+ variantType, //the type string of the "value", as determined by QVariant::typeName
2326+ typeString, //the type string of the StelProperty, as determined by QMetaProperty::typeName (may not be equal to "variantType")
2327+ typeEnum, //the enum value of the type of the StelProperty, as determined by StelProperty::getType
2328+ }
2329+}
2330+@endcode
2331+@note The generic type conversions are done by QJsonValue::fromVariant
2332+
2333+\subsubsection rcStelPropertyServicePOST POST operations
2334+Implemented by StelPropertyService::postImpl
2335+
2336+\paragraph rcStelPropertyServiceSet set
2337+Parameters: <tt>id (String) value (String)</tt>\n
2338+Sets the StelProperty identified by \p id to the value \p value. The value is converted to the StelProperty type
2339+using QVariant logic, an error is returned if this is somehow not possible.
2340+
2341+\subsection rcLocationService LocationService operations (/api/location/)
2342+\subsubsection rcLocationServiceGET GET operations
2343+Implemented by LocationService::getImpl
2344+
2345+\paragraph rcLocationServiceList list
2346+Returns the list of all stored location IDs (keys of StelLocationMgr::getAllMap) as JSON string array
2347+
2348+\paragraph rcLocationServiceCountrylist countrylist
2349+Returns the list of all known countries (StelLocaleMgr::getAllCountryNames), as a JSON array of objects of format
2350+@code
2351+{
2352+ name, //the english country name
2353+ name_i18n //the localized country name (current language)
2354+}
2355+@endcode
2356+
2357+\paragraph rcLocationServicePlanetlist planetlist
2358+Returns the list of all solar system planet names (SolarSystem::getAllPlanetEnglishNames), as a JSON array of objects of format
2359+@code
2360+{
2361+ name, //the english planet
2362+ name_i18n //the localized planet name (current language)
2363+}
2364+@endcode
2365+
2366+\paragraph rcLocationServicePlanetimage planetimage
2367+Parameters: <tt>planet (String)</tt>\n
2368+Returns the planet texture image for the \p planet (english name)
2369+
2370+\subsubsection rcLocationServicePOST POST operations
2371+Implemented by LocationService::postImpl
2372+
2373+\paragraph rcLocationServiceSetlocationfields setlocationfields
2374+Parameters: <tt>id (String) | ( [latitude (Number)] [longitude (Number)] [altitude (Number)] [name (String)] [country (String)] [planet (String)] )</tt>\n
2375+Changes and moves to a new location.
2376+If \p id is given, all other parameters are ignored, and a location is searched from the named locations using StelLocationMgr::locationForString with the \p id.
2377+Else, the other parameters change the specific field of the current StelLocation.
2378+
2379+\subsection rcLocationSearchService LocationSearchService operations (/api/locationsearch/)
2380+\subsubsection rcLocationSearchServiceGET GET operations
2381+Implemented by LocationSearchService::getImpl
2382+
2383+\paragraph rcLocationSearchServiceSearch search
2384+Parameters: <tt>term (String)</tt>\n
2385+Searches the \p term in the list of predefined locations of the StelLocationMgr, and returns a JSON string array of the results.
2386+
2387+\paragraph rcLocationSearchServiceNearby nearby
2388+Parameters: <tt>[planet (String)] [latitude (Number)] [longitude (Number)] [radius (Number)]</tt>\n
2389+Searches near the location defined by \p planet, \p latitude and \p longitude for predefined locations (inside the given \p radius)
2390+using StelLocationMgr::pickLocationsNearby, returns a JSON string array.
2391+
2392+\subsection rcViewService ViewService operations (/api/view/)
2393+\subsubsection rcViewServiceGET GET operations
2394+Implemented by ViewService::getImpl
2395+
2396+\paragraph rcViewServiceListlandscape listlandscape
2397+Lists the installed landscapes as a JSON object of format
2398+@code{.js}
2399+{
2400+ <landscapeId> : <landscapeName>, //maps the landscape id to the translated landscape name
2401+ ...
2402+}
2403+@endcode
2404+
2405+\paragraph rcViewServiceLandscapedescription landscapedescription/
2406+<em>Note that the slash at the end is mandatory!</em>\n
2407+Provides virtual filesystem access to the current landscape directory.
2408+The operation can take a longer path in the URL. The remainder is used to access files in the landscape directory.
2409+If no longer path is given, the current HTML landscape description (as per LandscapeMgr::getCurrentLandscapeHtmlDescription)
2410+is returned. An example: `landscapedescription/image.png` returns `image.png` from the current landscape directory.
2411+
2412+This operation allows to set up an HTML \c iframe or similar for the landscape description, including all images, etc. embedded
2413+in the HTML description.
2414+
2415+\paragraph rcViewServiceListskyculture listskyculture
2416+Lists the installed sky cultures as a JSON object of format
2417+@code{.js}
2418+{
2419+ <skycultureId> : <skycultureName>, //maps the id to the translated name
2420+ ...
2421+}
2422+@endcode
2423+
2424+\paragraph rcViewServiceSkyculturedescription skyculturedescription/
2425+<em>Note that the slash at the end is mandatory!</em>\n
2426+Provides virtual filesystem access to the current skyculture directory.
2427+The operation can take a longer path in the URL. The remainder is used to access files in the skyculture directory.
2428+If no longer path is given, the current HTML skyculture description (as per StelSkyCultureMgr::getCurrentSkyCultureHtmlDescription)
2429+is returned. An example: `skyculturedescription/image.png` returns `image.png` from the current skyculture directory.
2430+
2431+This operation allows to set up an HTML \c iframe or similar for the skycultures description, including all images, etc. embedded
2432+in the HTML description.
2433+
2434+\paragraph rcViewServiceListprojection listprojection
2435+Lists the available projection types as a JSON object of format
2436+@code{.js}
2437+{
2438+ <projectionTypeKey> : <projectionName>, //maps the id to the translated name
2439+ ...
2440+}
2441+@endcode
2442+
2443+\paragraph rcViewServiceProjectiondescription projectiondescription
2444+Returns the HTML description of the current projection (StelProjector::getHtmlSummary)
2445+
2446+*/
2447
2448=== added file 'plugins/RemoteControl/doc/remoteControlWeb.doxygen'
2449--- plugins/RemoteControl/doc/remoteControlWeb.doxygen 1970-01-01 00:00:00 +0000
2450+++ plugins/RemoteControl/doc/remoteControlWeb.doxygen 2016-06-12 13:59:22 +0000
2451@@ -0,0 +1,564 @@
2452+/*
2453+ * Stellarium
2454+ * Copyright (C) 2016 Florian Schaukowitsch
2455+ *
2456+ * This program is free software; you can redistribute it and/or
2457+ * modify it under the terms of the GNU General Public License
2458+ * as published by the Free Software Foundation; either version 2
2459+ * of the License, or (at your option) any later version.
2460+ *
2461+ * This program is distributed in the hope that it will be useful,
2462+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2463+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2464+ * GNU General Public License for more details.
2465+ *
2466+ * You should have received a copy of the GNU General Public License
2467+ * along with this program; if not, write to the Free Software
2468+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2469+ */
2470+
2471+/*!
2472+
2473+\page remoteControlWeb %RemoteControl plugin web interface
2474+
2475+\tableofcontents
2476+
2477+The \ref remoteControlDoc "RemoteControl plugin", by default, provides a HTML web interface through the same integrated HTTP
2478+server that serves the \ref remoteControlApi "RemoteControl API". All content found in the <tt>data/webroot</tt> folder is served.
2479+Note that the \c /api/ path is reserved for the \ref remoteControlApi "HTTP API", and therefore can not be used as a folder.
2480+The <tt>index.html</tt> file is mapped to the root, so you can access it using http://localhost:8090 with the default port setting
2481+of 8090. A slightly modified alternative interface (mainly larger buttons for now) for 7" tablets and other touch devices
2482+is available at http://localhost:8090/tablet7in.html.
2483+
2484+A reasonably modern browser is required to access the interface. Some features of <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5">HTML5</a>
2485+and <a href="https://developer.mozilla.org/en/docs/Web/CSS/CSS3">CSS3</a> are used.
2486+
2487+The interface heavily relies on <a href="https://jquery.com/">jQuery</a> for easier JavaScript coding. The code is structured into modules,
2488+and loaded using <a href="http://requirejs.org/">require.js</a>, which automatically resolves dependencies and load order.
2489+
2490+\section remoteControlWebStructure File and directory structure
2491+
2492+Note that not all files are listed here, only those of special interest.
2493+
2494+- webroot/ - root directory
2495+ - index.html - Default interface, also mapped to the root folder
2496+ - style.css - Main stylesheet
2497+ - tablet7in.html - Modified interface for tablet devices
2498+ - style_tablet7in.css - Additional stylesheet for tablet7in.html
2499+ - translate_files - Defines which files are passed through StelTranslator, see \ref remoteControlWebTranslation
2500+ - iframestyle.css - defines the style for internal frames (landscape description, etc.)
2501+ - /js/ - Contains the JavaScript files required for the interfaces
2502+ - main.js - This is the configuration file for require.js. Loads \ref rcUiMainui as main module.
2503+ - settings.js - Contains some configuration options for the web interface
2504+ - translationdata.js - Auto-generated file containing strings to translate through StelTranslator, see \ref remoteControlWebTranslation
2505+ - /api/ - Contains .js modules that define the connection to the \ref remoteControlApi "RemoteControl API"
2506+ - \ref rcApiRemotecontrol
2507+ - \ref rcApiActions
2508+ - \ref rcApiFlags
2509+ - \ref rcApiLocation
2510+ - \ref rcApiProperties
2511+ - \ref rcApiScripts
2512+ - \ref rcApiSearch
2513+ - \ref rcApiTime
2514+ - \ref rcApiUpdatequeue
2515+ - \ref rcApiViewcontrol
2516+ - \ref rcApiViewoptions
2517+ - /ui/ - Contains UI-related .js modules which depend on the /api/ .js modules
2518+ - \ref rcUiMainui
2519+ - \ref rcUiActions
2520+ - \ref rcUiCombobox
2521+ - \ref rcUiJqueryuifixes
2522+ - \ref rcUiLocation
2523+ - \ref rcUiScripts
2524+ - \ref rcUiSearch
2525+ - \ref rcUiTime
2526+ - \ref rcUiViewcontrol
2527+ - \ref rcUiViewoptions
2528+
2529+\section remoteControlWebEdit Editing the interface
2530+
2531+With knowledge of HTML, CSS and JavaScript (the latter not required for basic modifications), the interface can be customized.
2532+
2533+\subsection remoteControlWebBasic Basic extension
2534+
2535+When using the standard JavaScript provided, they allow to use pre-defined CSS "marker" classes which do not style the element per-se (i.e. have no entries in the .css files),
2536+but allow you to add functionality to HTML elements without editing the JavaScript code.
2537+Some of these classes also allow you to add further attributes to the element
2538+(usually <a href="https://developer.mozilla.org/en/docs/Web/Guide/HTML/Using_data_attributes">HTML5 data attributes</a>)
2539+to further customize their behaviour.
2540+
2541+\subsubsection remoteControlWebUIClasses UI control classes
2542+
2543+Some classes allow generating UI controls that are similar to what you expect for desktop apps. These use <a href="https://jqueryui.com/">jQuery UI</a> with
2544+some modifications.
2545+
2546+\paragraph remoteControlWebUIspinner spinner
2547+If added to an HTML \c input element, it sets the control up as a numerical Spinner widget (using jQuery UI: https://api.jqueryui.com/spinner/).
2548+It supports the following optional parameters:
2549+- \p data-min - Defines the minimum value of the spinner
2550+- \p data-max - Defines the maximum value of the spinner
2551+- \p data-step - Defines the desired step size of the spinner, default is 1. May be different from the number format.
2552+- \p data-numberformat - Defines how the number is formatted, using <a href="https://github.com/jquery/globalize/blob/v0.1.1/README.md#numbers">globalize.js 0.1.1 syntax</a>
2553+
2554+The element will emit the custom \c spinuserinput event whenever the value changes (either through the buttons or direct keyboard input).
2555+An example, showing how a spinner is created and handled:
2556+\code
2557+//make a spinner from -50 to 50, always showing 2 decimal points and stepping 0.1 per click
2558+<input id="myspinner" class="spinner" data-min="-50" data-max="50" data-step="0.1" data-numberformat="n2"/>
2559+
2560+//input handling in javascript
2561+$("#myspinner").on("spinuserinput", function(evt,ui) {
2562+ //print the new value
2563+ console.log(ui.value);
2564+});
2565+\endcode
2566+
2567+\paragraph remoteControlWebUIslider slider
2568+If added to an HTML \c div element, it sets the control up as a numerical slider widget (using jQuery UI: https://api.jqueryui.com/slider/).
2569+It supports the following optional parameters:
2570+- \p data-min - Defines the minimum value of the slider
2571+- \p data-max - Defines the maximum value of the slider
2572+- \p data-step - Defines the desired step size of the slider, default is 1. May be different from the number format.
2573+
2574+The element will emit the \c slide event when the slider is moved.
2575+\code
2576+//make a slider from -50 to 50, stepsize 0.1
2577+<div id="myslider" class="slider" data-min="-50" data-max="50" data-step="0.1"/>
2578+
2579+//input handling in javascript
2580+$("#myslider").on("slide", function(evt,ui) {
2581+ //print the new value
2582+ console.log(ui.value);
2583+});
2584+\endcode
2585+
2586+\paragraph remoteControlWebUIjquerybutton jquerybutton
2587+If added to an HTML \c button element, it converts it to a <a href="https://jqueryui.com/button/">jQuery UI button</a>.
2588+This is mainly a cosmetic operation.
2589+
2590+\paragraph remoteControlWebUIselectmenu selectmenu
2591+If added to an HTML \c select element, it creates a <a href="https://jqueryui.com/selectmenu/">jQuery UI selectmenu</a> from it.
2592+This allows simple popup selection menus (like a QComboBox).
2593+
2594+\subsubsection remoteControlWebProp Special behaviour classes
2595+These classes allow automatic connection to StelProperty and StelAction elements defined in Stellarium, allowing particularly easy
2596+extension of the web interface.
2597+
2598+\paragraph remoteControlWebstelproperty stelproperty (Connection to StelProperty)
2599+Allows direct connection of an element to a StelProperty, meaning the element is automatically updated
2600+whenever the value in Stellarium changes --- regardless of the source of the change: it can come from the main GUI, scripting, or even
2601+other RemoteControl web interface instances! Together with the \ref remoteControlWebUIClasses listed above, this allows closely and easily recreating
2602+standard Stellarium interface elements. This is supported for:
2603+- \c input elements with the \c spinner class (for numerical properties)\n
2604+ The StelProperty to use is identified by the standard \c input attribute \p name.
2605+ Updates the \p value property of the \c input when the StelProperty changes, and reacts to \c spinuserinput events to update the property
2606+
2607+- \c input elements of type \c checkbox (`<input type="checkbox">` (for boolean properties)\n
2608+ The StelProperty to use is identified by the standard \c input attribute \p name.
2609+ Uses the \p checked property and the \c click event.
2610+
2611+- \c div elements with the \c slider class (for numerical properties)\n
2612+ The StelProperty to use is identified by the custom attribute \p data-prop.
2613+ Connects to the \c slider widget property \p value.
2614+
2615+- \c select elements (also supports the optional \c selectmenu classs)\n
2616+ The StelProperty to use is identified by the standard \c select attribute \p name.
2617+ Sets the \c option that has the same \p value as the StelProperty value.
2618+ Useful for single selection out of a list of possibilities.
2619+
2620+- \c span elements, for read-only property display with optional number format\n
2621+ The StelProperty to use is identified by the custom attribute \p data-prop.
2622+ The value is displayed using the element's text content.
2623+ The optional \p data-numberformat attribute is used for the number format
2624+ using [globalize.js 0.1.1 syntax](https://github.com/jquery/globalize/blob/v0.1.1/README.md#numbers)
2625+
2626+- \c button or `input[type="button"]` elements, for write-only setting of a StelProperty to a pre-defined value when clicked\n
2627+ The StelProperty to use is identified by the standard attribute \p name,
2628+ and the value to set it to is defined by the attribute \p value.
2629+
2630+An example, setting up a spinner for the \c MilkyWay.intensity StelProperty:
2631+\code{.html}
2632+<!-- this is all that is required, the rest is done automatically -->
2633+<input class="spinner stelproperty" name="MilkyWay.intensity" data-min="0" data-max="10" data-step="0.1" data-numberformat="n2"/>
2634+\endcode
2635+
2636+Many more examples can be found by studying the `index.html` code.
2637+
2638+\paragraph remoteControlWebstelaction stelaction (Connection to StelAction)
2639+When this class is added to \c button elements or \c input elements of `type="button"` or `type="checkbox"`,
2640+this connects the control to a StelAction. The action is identified by the \p name attribute.
2641+If the action is a boolean action (i.e. StelAction::isCheckable is true), checkboxes show the current state of the action,
2642+and buttons get the \c active CSS class assigned if the action is currently true.
2643+
2644+Examples:
2645+\code{.html}
2646+<!-- This is how the main bottom button bar is defined -->
2647+<ul class="ui-corner-all ui-widget-content button32list margin-vertical">
2648+ <li><button class="stelaction icon32 btConstellationLines" name="actionShow_Constellation_Lines"></button></li>
2649+ <li><button class="stelaction icon32 btConstellationLabels" name="actionShow_Constellation_Labels"></button></li>
2650+ <li><button class="stelaction icon32 btConstellationArt" name="actionShow_Constellation_Art"></button></li>
2651+ <li><button class="stelaction icon32 btEquatorialGrid" name="actionShow_Equatorial_Grid"></button></li>
2652+ <li><button class="stelaction icon32 btAzimuthalGrid" name="actionShow_Azimuthal_Grid"></button></li>
2653+ <li><button class="stelaction icon32 btGround" name="actionShow_Ground"></button></li>
2654+ <li><button class="stelaction icon32 btCardinalPoints" name="actionShow_Cardinal_Points"></button></li>
2655+ <li><button class="stelaction icon32 btAtmosphere" name="actionShow_Atmosphere"></button></li>
2656+ <li><button class="stelaction icon32 btNebula" name="actionShow_Nebulas"></button></li>
2657+ <li><button class="stelaction icon32 btPlanets" name="actionShow_Planets_Labels"></button></li>
2658+ <li><button class="stelaction icon32 btEquatorialMount" name="actionSwitch_Equatorial_Mount"></button></li>
2659+ <li><button class="stelaction icon32 btGotoSelectedObject" name="actionSet_Tracking"></button></li>
2660+ <li><button class="stelaction icon32 btNightView" name="actionShow_Night_Mode"></button></li>
2661+ <li><button class="stelaction icon32 btFullScreen" name="actionSet_Full_Screen_Global"></button></li>
2662+</ul>
2663+
2664+<!-- This is how to set up checkboxes -->
2665+<label><input type="checkbox" class="stelaction" name="actionShow_Planets" /><?= tr("Show Solar System objects")?></label>
2666+<label><input type="checkbox" class="stelaction" name="actionShow_Planets_Hints" /><?= tr("Show planet markers")?></label>
2667+<label><input type="checkbox" class="stelaction" name="actionShow_Planets_Orbits" /><?= tr("Show planet orbits")?></label>
2668+\endcode
2669+
2670+\paragraph remoteControlWebStelssc stelssc (Direct script execution)
2671+This class allows you to define buttons that directly execute Stellarium \ref scripting code.
2672+Supported for \c button and \c input elements of type \p button. The code to execute should be stored inside
2673+the element's \p value property. If the custom attribute \p data-useincludes attribute is added (with any value),
2674+the default include folder is added for optional includes, but this is not recommended unless necessary.
2675+
2676+An example:
2677+\code{.html}
2678+<!-- some buttons which move the view to predefined angles -->
2679+<button type="button" class="stelssc" value="core.moveToAltAzi(0., 0., 3.)">0&deg;</button>
2680+<button type="button" class="stelssc" value="core.moveToAltAzi(0., 30., 3.)">30&deg;</button>
2681+<button type="button" class="stelssc" value="core.moveToAltAzi(0., 60., 3.)">60&deg;</button>
2682+<button type="button" class="stelssc" value="core.moveToAltAzi(0., 90., 3.)">90&deg;</button>
2683+<button type="button" class="stelssc" value="core.moveToAltAzi(0., 120., 3.)">120&deg;</button>
2684+<button type="button" class="stelssc" value="core.moveToAltAzi(0., 150., 3.)">150&deg;</button>
2685+<button type="button" class="stelssc" value="core.moveToAltAzi(0., 180., 3.)">180&deg;</button>
2686+<button type="button" class="stelssc" value="core.moveToAltAzi(0., 210., 3.)">210&deg;</button>
2687+<button type="button" class="stelssc" value="core.moveToAltAzi(0., 240., 3.)">240&deg;</button>
2688+<button type="button" class="stelssc" value="core.moveToAltAzi(0., 270., 3.)">270&deg;</button>
2689+<button type="button" class="stelssc" value="core.moveToAltAzi(0., 300., 3.)">300&deg;</button>
2690+<button type="button" class="stelssc" value="core.moveToAltAzi(0., 330., 3.)">330&deg;</button>
2691+\endcode
2692+
2693+\warning
2694+The \c stelssc approach has some disadvantages, so try to use it only when necessary:
2695+- causes a larger overhead for Stellarium internally than other methods provided by the web interface
2696+- the scripts can't be executed if another script is currently running, an error message will be shown in this case
2697+ - this also includes the user clicking too fast on any \c stelssc buttons!
2698+
2699+\paragraph remoteControlWebStelplugin stelplugin (Plugin-specific sections)
2700+With the CSS class \c stelplugin, one can create special HTML sections that
2701+are only shown when a specified [plugin](\ref plugins) is currently loaded by Stellarium.
2702+If the plugin is not loaded, the whole element and all it's children are removed from the DOM.
2703+This class can be added to any element. The plugin which is required is defined by the
2704+\c data-plugin attribute, which should be set to the plugin ID.
2705+
2706+The optional \c data-pluginjs attribute can be used to define an additional JavaScript module that is only
2707+loaded when the plugin is loaded. This can be used to implement additional behaviour through JS, if required.
2708+It is recommended to put these modules into the `webroot/js/plugins` folder.
2709+
2710+An example, defining the plugin panel for the \ref archaeoLines :
2711+\code
2712+<div id="vo_archaeolines" class="smallblock stelplugin" data-plugin="ArchaeoLines" data-pluginjs="plugins/archaeolines">
2713+ <h3><label><input type="checkbox" class="stelaction valign-middle" name="actionShow_Archaeo_Lines"/><?= tr("ArchaeoLines")?></label></h3>
2714+ <div class="inline-block blocklabel">
2715+ <label><input type="checkbox" class="stelaction" name="actionAL_showEquinoxLine"/><?= tr("Equinox")?></label>
2716+ <label><input type="checkbox" class="stelaction" name="actionAL_showSolsticeLines"/><?= tr("Solstices")?></label>
2717+ <label><input type="checkbox" class="stelaction" name="actionAL_showCrossquarterLines"/><?= tr("Crossquarters")?></label>
2718+ <label><input type="checkbox" class="stelaction" name="actionAL_showMajorStandstillLines"/><?= tr("Major Standstill")?></label>
2719+ <label><input type="checkbox" class="stelaction" name="actionAL_showMinorStandstillLines"/><?= tr("Minor Standstill")?></label>
2720+ </div>
2721+ <div class="inline-block blocklabel">
2722+ <label><input type="checkbox" class="stelaction" name="actionAL_showZenithPassageLine"/><?= tr("Zenith Passage")?></label>
2723+ <label><input type="checkbox" class="stelaction" name="actionAL_showNadirPassageLine"/><?= tr("Nadir Passage")?></label>
2724+ <label><input type="checkbox" class="stelaction" name="actionAL_showSelectedObjectLine"/><?= tr("Selected Object")?></label>
2725+ <label><input type="checkbox" class="stelaction" name="actionAL_showCurrentSunLine"/><?= tr("Current Sun")?></label>
2726+ <label><input type="checkbox" class="stelaction" name="actionAL_showCurrentMoonLine"/><?= tr("Current Moon")?></label>
2727+ </div>
2728+ <label class="display-block" for="select_ArchaeoLines_enumShowCurrentPlanet"><?= tr("Current Planet:")?></label>
2729+ <select id="select_ArchaeoLines_enumShowCurrentPlanet" class="selectmenu stelproperty display-block" name="ArchaeoLines.enumShowCurrentPlanet">
2730+ <option value="10"><?= tr("None")?></option>
2731+ <option value="11"><?= tr("Mercury")?></option>
2732+ <option value="12"><?= tr("Venus")?></option>
2733+ <option value="13"><?= tr("Mars")?></option>
2734+ <option value="14"><?= tr("Jupiter")?></option>
2735+ <option value="15"><?= tr("Saturn")?></option>
2736+ </select>
2737+</div>
2738+
2739+//the contents of plugins/archaeolines.js
2740+define(["jquery"],function($){
2741+ "use strict";
2742+
2743+ //this is just an example how to use additional dynamically loaded plugin files
2744+ console.log("Hello, this is a asynchronously loaded plugin javascript file!");
2745+
2746+});
2747+\endcode
2748+
2749+\subsection remoteControlWebTranslation Translation information
2750+
2751+The interface can be translated using methods similar to the main program.
2752+All strings in the HTML markup that should be translated can be written
2753+between pseudo-PHP style tags and the \c tr function to achieve the same effect as the `q_()` macro in C++, like so:
2754+\code
2755+<label><input type="checkbox" class="stelaction" name="actionShow_Planets" /><?= tr("Show Solar System objects")?></label>
2756+\endcode
2757+
2758+All files which are listed in the `webroot/translate_files` file will be parsed, and all `<?= tr("----")?>` tags will be
2759+replaced using the StelTranslator for the current application language.
2760+
2761+If you require translated strings through JavaScript, you should use the `tr` method of the \ref rcApiRemotecontrol module,
2762+which also works similar to the `q_()` macro. There is a special procedure for the JavaScript strings: the target
2763+\c RemoteControl-update-translationdata should be run whenever new JavaScript strings have been added.
2764+This updates the file `webroot/js/translationdata.js` with all current `tr()` strings. [Python](https://www.python.org/)
2765+is required to be installed for this operation.
2766+
2767+Like the main program, the strings can be extracted from the HTML/JS code using gettext/xgettext. There are CMake targets for this like
2768+for the C++ code (\c generate-pot-stellarium-remotecontrol, \c update-po-stellarium-remotecontrol, etc.) and they are also executed
2769+with the combined targets (\c generate-pot, \c update-po etc.).
2770+
2771+\subsection remoteControlJS JavaScript module reference
2772+
2773+All interface code is developed using [require.js modules](http://requirejs.org/docs/api.html#define).
2774+This allows defining the dependencies of each module, as well as easier maintainability.
2775+Each module should be defined in its own .js file. The module ID corresponds to the .js file name
2776+without the file extension.
2777+
2778+In short, to define a module, wrap it in a \c define call, and optionally add dependencies.
2779+A basic example (for more ways to do it see the require.js doc):
2780+\code
2781+//myawesomemodule.js
2782+//the IDs of the dependencies are listed in an array as first parameter
2783+//the second parameter is usually a function which takes the actual instances of the dependencies as a parameter,
2784+// in the same order as they are in the array!
2785+define(["jquery", "api/remotecontrol"], function($,rc) {
2786+ "use strict"; //it is recommended to use strict mode for each module
2787+
2788+ //do something as soon as this module is loaded
2789+ console.log("my awesome module is being loaded!");
2790+
2791+ //do something when the DOM is ready (because that is not guaranteed while the module is first bein loaded!)
2792+ $(function(){
2793+ console.log("the document is ready, you can access the elements now!");
2794+ //access an element and modifiy it
2795+ $("#myelement").text("hey, this is awesome");
2796+ });
2797+
2798+ //react to the serverDataReceived event of the remotecontrol module
2799+ $(rc).on("serverDataReceived", function(evt,data) {
2800+ console.log("Stellarium just sent us new data!");
2801+ console.log("The current jDay is " + data.time);
2802+ });
2803+
2804+ //provide some public methods that other modules may call
2805+ return {
2806+ myAwesomeMethod: function() {
2807+ console.log("Hello there!");
2808+ }
2809+ };
2810+});
2811+
2812+//another module (in another file) can now reference our module as dependency to load it and use its methods
2813+define(["jquery", "myawesomemodule"],function($, awesome) {
2814+
2815+ awesome.myAwesomeMethod(); //prints "Hello there!"
2816+});
2817+\endcode
2818+
2819+The UI modules can depend on the API modules and other UI modules.
2820+The API modules can depend on other API modules.
2821+Circular dependencies should of course be avoided.
2822+
2823+\subsubsection rcApiRemotecontrol api/remotecontrol
2824+
2825+This is the main API module, with no further dependencies on other API modules.
2826+
2827+Its main function is that it provides automatic status updates by periodically polling (by default each second) the
2828+\c status operation of the MainService. Whenever this poll succeeds, the \c serverDataReceived custom event is emitted,
2829+with the JSON response of the server as \p data parameter. Other API modules should use this event, and process
2830+the data in which they are interested.
2831+It also keeps track of StelAction and StelProperty changes,
2832+and emits \c stelActionsChanged and/or \c stelPropertiesChanged, if necessary. Note that it does not process them further,
2833+this is the job of the \ref rcApiActions and \ref rcApiProperties modules, respectively.
2834+When the connection to the server is lost (i.e. the polling returned an error), the \c serverDataError event is sent.
2835+
2836+The other main function is that it provides the \c postCmd method, which is a simple wrapper around an AJAX POST call
2837+that is intended to be used by other modules to send commands to the server. It also includes the \c tr method used
2838+for [translating JS strings](\ref remoteControlWebTranslation).
2839+
2840+Finally, this module also processes the [plugin-specific sections](\ref remoteControlWebStelplugin) on load.
2841+
2842+\subsubsection rcApiActions api/actions
2843+
2844+Processes StelAction related events. Whenever it detects that boolean StelAction was changed, it emits two events:
2845+- A generic event \c stelActionChanged with the \c actionId as a parameter. This can be used when interested in ALL action changes
2846+ (like for a action list)
2847+- A specialied event `stelActionChanged:<actionId>` with the \c actionId as part of the event name.
2848+ This can be used when listening for a specific action only.
2849+
2850+On the first load of the interface, it loads a list of all actions (using the ActionService \c list operation) and emits the
2851+\c actionListLoaded event when this data is available.
2852+
2853+To execute/toggle an action, it provides the public \c executeAction method, which just requires the action ID as parameter.
2854+To find out whether an action is currently checked, use the \c isChecked method.
2855+
2856+\subsubsection rcApiFlags api/flags
2857+
2858+This is a utility module, which can be used to implement checkboxes for enum flag types, where each checkbox sets a
2859+specific bit of a single value. The module should be constructed with \c new, the constructor takes the parent element of a list of
2860+checkboxes (\c input of type checkbox) and a method which is called back when the internal value changes (i.e. the user clicks a checkbox). It provides the
2861+\c setValue method to set the current value and check the correct checkboxes. The bit value of each \c input should be specified
2862+as its \p value property, in hexadecimal string format (for example `0x0004`)
2863+
2864+\subsubsection rcApiLocation api/location
2865+
2866+Module which connects to the LocationService and the LocationSearchService.
2867+It emits the following events whenever the specified field changed:
2868+\c planetChanged,\c nameChanged, \c countryChanged, \c altitudeChanged, \c latitudeChanged, \c longitudeChanged, \c positionChanged (emitted when either lat or lon changed)
2869+
2870+It also has \c set methods for these fields.
2871+Furthermore, it provides \c performLocationSearch, which searches the predefined locations for a specific search string,
2872+and \c performNearbySearch, which searches predefined locations near a given lat/lon on the current planet.
2873+These methods take a callback parameter to notify the caller of the results.
2874+The \c setLocationById method can then be used to set the location to a result of these 2 methods.
2875+
2876+It also provides a \c loadCountryList and a \c loadPlanetList which load the specified lists and return the results with a callback.
2877+
2878+\subsubsection rcApiProperties api/properties
2879+
2880+Processes StelProperty related things. Like the \ref rcApiActions module, it emits 2 events when it detects a StelProperty changed:
2881+- A generic event \c stelPropertyChanged with the \c propertyId as a parameter. This can be used when interested in ALL property changes
2882+ (like for a list)
2883+- A specialied event `stelPropertyChanged:<propertyId>` with the \c propertyId as part of the event name.
2884+ This can be used when listening for a specific property only.
2885+
2886+It provides \c getStelProp and \c setStelProp methods which retrieve and set the value of a StelProperty,
2887+and also a \c setStelPropQueued convenience method to batch multiple fast interface changes (e.g. through a slider or spinner)
2888+into a single \c setStelProp call which is only executed after a small time has passed with no changes.
2889+
2890+It also emits the \c propertyListLoaded event when it first loads the full list of StelProperties with their type information.
2891+
2892+\subsubsection rcApiScripts api/scripts
2893+
2894+This module handles script execution (i.e. connection to the ScriptService). It provides the following methods:
2895+- \c loadScriptList - loads the list of all scripts, takes a callback to return this data
2896+- \c runScript - runs the specified script id
2897+- \c runDirectScript - directly runs the given script code
2898+- \c stopScript - stops a currently running script
2899+
2900+It also emits the \c activeScriptChanged event whenever it detects that the current script has changed or started/stopped
2901+
2902+\subsubsection rcApiSearch api/search
2903+
2904+Implements object search functionality, connecting to the ObjectService and the SimbadService. The following methods are provided:
2905+- \c loadObjectTypes - loads the list of object types, takes a callback
2906+- \c loadObjectList - loads the list of objects of a specified type, can return english or localized names
2907+- \c selectObjectByName - selects the object that matches the specified name
2908+- \c focusPosition - focuses the given coordinate (array of 3 numbers) in the J2000 frame
2909+- \c performSearch - performs an object lookup in Stellarium's internal catalog and Simbad. In addition to the search string,
2910+ 2 callbacks must be given as parameters: one for the catalog results, and one for the simbad results. If a search is currently running,
2911+ it is aborted (meaning the callbacks won't be called for the old searches), allowing this method to be repeatedly called while
2912+ the user is typing. The Simbad search is only started after a small interval without typing, to reduce the overhead of the
2913+ external web requests.
2914+
2915+While a search is running, it emits \c simbadStateChange events to notify the UI of the current state of the lookup.
2916+
2917+\subsubsection rcApiTime api/time
2918+
2919+Contains time-related functions and conversions, similar to what StelCore does. This module keeps it's own sense of Stellariums current time,
2920+to provide an updated interface even between the \c status polls of the \ref rcApiRemotecontrol module.
2921+
2922+It provides following methods:
2923+- \c getCurrentTime - calculates the best guess to the current Stellarium simulation time. This depends on the information received with the last \c status poll,
2924+ the time since the last data was received and the time the last time change was performed
2925+- \c isRealTimeSpeed - true if the simulation time currently flows at the same rate as the real time (1 sec per sec).
2926+- \c jdayToDate - converts a jDay (single number) to Day/Month/Year format, this returns a JS object with \p day, \p month, \p year fields instead
2927+ of a JS Date object because of its limitations.
2928+- \c jdayToDate - returns the time component of the given jDay, as a JS object with \p hour, \p minute, \p second fields
2929+- \c dateTimeToJd - converts a time given in Y/M/D-H/MIN/S format to a jDay
2930+- \c dateTimeForRollover - like StelUtils::changeDateTimeForRollover
2931+- \c isTimeUpdatePending - if true, there is a time change which has not yet been sent to the server
2932+- \c increaseTimeRate - increases the Stellarium simulation time rate (like StelCore::increaseTimeSpeed)
2933+- \c decreaseTimeRate - decreases the Stellarium simulation time rate (like StelCore::decreaseTimeSpeed)
2934+- \c isRewind - returns true if the time currently flows backwards (at least at -0.99 sec / sec)
2935+- \c isFastForward - returns true if time currently is flowing faster than real time
2936+- \c isTimeNow - returns true if the current simulation time is very close to the actual system time
2937+- \c isTimeStopped - returns true if the simulation time rate is zero
2938+- \c togglePlayPause - toggles between timerates 0 and 1 sec/sec
2939+- \c setDateNow - sets the simulation time to the current system time
2940+- \c setJDay - sets the time to the specified JDay
2941+- \c setTimeFromTimeObj - sets the time from a "time object", containing both date and time in the following format
2942+\code
2943+{
2944+ date : {
2945+ year, month, day
2946+ },
2947+ time : {
2948+ hour, minute, second
2949+ }
2950+}
2951+\endcode
2952+- \c getTimeData - returns the current time data, containing the last response from the server (including timezone info, etc)
2953+ The event \c timeDataUpdated is sent whenever this changes.
2954+
2955+\subsubsection rcApiUpdatequeue api/updatequeue
2956+
2957+This implements a simple update queue class that updates the server after a specified interval if the user does nothing else inbetween.
2958+This is used to limit the rate at which updates are sent to the server. The \c UpdateQueue constructor takes an url and a callback for the result,
2959+and when the interface needs to send an update, \c enqueue can be called with the data to send.
2960+
2961+\subsubsection rcApiViewcontrol api/viewcontrol
2962+
2963+Implements the %FOV access and viewport movement methods. Use \c setFOV to set the %FOV, the \c fovChanged event is sent whenever the %FOV changes.
2964+There are \c moveRight, \c moveUp, \c moveUpRight etc. methods that allow the user to move the viewport. To stop the movement, use \c stopMovement.
2965+
2966+\subsubsection rcApiViewoptions api/viewoptions
2967+
2968+Implements the loading of the projection, landscape and skyculture lists.
2969+
2970+\subsubsection rcUiMainui ui/mainui
2971+
2972+This is the main module of the interface. It lists all the other UI modules as a dependency.
2973+It starts of the update look of the \c rcApiRemotecontrol module, handles the automatic generation
2974+of the [special controls](\ref remoteControlWebUIClasses) and [connection of StelProperty controls](\ref remoteControlWebstelproperty),
2975+and performs smooth animation of the time controls. It also keeps track of the current interface tab the user is on, and
2976+restores it when the page is reloaded.
2977+
2978+\subsubsection rcUiActions ui/actions
2979+
2980+Implements the action list and the [StelAction buttons and checkboxes](\ref remoteControlWebstelaction).
2981+
2982+\subsubsection rcUiCombobox ui/combobox
2983+
2984+Implements a custom combobox control, on top of the jQuery UI \c autocomplete control. This is used for example in the location controls.
2985+
2986+\subsubsection rcUiJqueryuifixes ui/jqueryuifixes
2987+
2988+Includes some fixes to the standard jQuery UI control classes, especially for the spinner, to provide a unified
2989+change event, prevent non-numeric input and better touch support. This module is automatically loaded whenever other modules
2990+load the "jquery-ui" module.
2991+
2992+\subsubsection rcUiLocation ui/location
2993+
2994+Implements the location controls, such as the map which can be clicked and the comboboxes for the current location.
2995+
2996+\subsubsection rcUiScripts ui/scripts
2997+
2998+Implements the script list and shows the active script.
2999+
3000+\subsubsection rcUiSearch ui/search
3001+
3002+Implements the object search panel and the quick select buttons.
3003+
3004+\subsubsection rcUiTime ui/time
3005+
3006+Implements the time controls, the \c updateTimeDisplay method is called repeatedly as an animation by the \ref rcUiMainui module.
3007+
3008+\subsubsection rcUiViewcontrol ui/viewcontrol
3009+
3010+Implements the %FOV slider and the "virtual joystick" for the viewport movement.
3011+
3012+\subsubsection rcUiViewoptions ui/viewoptions
3013+
3014+Implements the projection, landscape and skyculture lists, and some minor things related to other view options.
3015+*/
3016
3017=== added directory 'plugins/RemoteControl/resources'
3018=== added file 'plugins/RemoteControl/resources/bt_network_templates.tif'
3019Binary files plugins/RemoteControl/resources/bt_network_templates.tif 1970-01-01 00:00:00 +0000 and plugins/RemoteControl/resources/bt_network_templates.tif 2016-06-12 13:59:22 +0000 differ
3020=== added file 'plugins/RemoteControl/resources/bt_remote_off.png'
3021Binary files plugins/RemoteControl/resources/bt_remote_off.png 1970-01-01 00:00:00 +0000 and plugins/RemoteControl/resources/bt_remote_off.png 2016-06-12 13:59:22 +0000 differ
3022=== added file 'plugins/RemoteControl/resources/bt_remote_on.png'
3023Binary files plugins/RemoteControl/resources/bt_remote_on.png 1970-01-01 00:00:00 +0000 and plugins/RemoteControl/resources/bt_remote_on.png 2016-06-12 13:59:22 +0000 differ
3024=== added directory 'plugins/RemoteControl/src'
3025=== added file 'plugins/RemoteControl/src/APIController.cpp'
3026--- plugins/RemoteControl/src/APIController.cpp 1970-01-01 00:00:00 +0000
3027+++ plugins/RemoteControl/src/APIController.cpp 2016-06-12 13:59:22 +0000
3028@@ -0,0 +1,141 @@
3029+/*
3030+ * Stellarium Remote Control plugin
3031+ * Copyright (C) 2015 Florian Schaukowitsch
3032+ *
3033+ * This program is free software; you can redistribute it and/or
3034+ * modify it under the terms of the GNU General Public License
3035+ * as published by the Free Software Foundation; either version 2
3036+ * of the License, or (at your option) any later version.
3037+ *
3038+ * This program is distributed in the hope that it will be useful,
3039+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3040+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3041+ * GNU General Public License for more details.
3042+ *
3043+ * You should have received a copy of the GNU General Public License
3044+ * along with this program; if not, write to the Free Software
3045+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
3046+ */
3047+
3048+#include "APIController.hpp"
3049+#include <QJsonDocument>
3050+
3051+
3052+APIController::APIController(int prefixLength, QObject* parent) : HttpRequestHandler(parent), m_prefixLength(prefixLength)
3053+{
3054+
3055+}
3056+
3057+APIController::~APIController()
3058+{
3059+
3060+}
3061+
3062+void APIController::update(double deltaTime)
3063+{
3064+ mutex.lock();
3065+ foreach(AbstractAPIService* service, m_serviceMap)
3066+ {
3067+ service->update(deltaTime);
3068+ }
3069+ mutex.unlock();
3070+}
3071+
3072+void APIController::registerService(AbstractAPIService *service)
3073+{
3074+ m_serviceMap.insert(service->serviceName(), service);
3075+}
3076+
3077+void APIController::service(HttpRequest &request, HttpResponse &response)
3078+{
3079+ //disable caching by default for services
3080+ response.setHeader("Cache-Control","no-cache");
3081+ //default content type is text
3082+ response.setHeader("Content-Type","text/plain");
3083+
3084+ //use the raw path here
3085+ QByteArray path = request.getRawPath();
3086+ QByteArray pathWithoutPrefix = path.right(path.size()-m_prefixLength);
3087+
3088+ int slashIdx = pathWithoutPrefix.indexOf('/');
3089+
3090+ QByteArray serviceString = pathWithoutPrefix;
3091+ QByteArray operation;
3092+ if(slashIdx>=0)
3093+ {
3094+ serviceString = pathWithoutPrefix.mid(0,slashIdx);
3095+ operation = pathWithoutPrefix.mid(slashIdx+1);
3096+ }
3097+
3098+ //try to find service
3099+ //the mutex here is to prevent a very strange crash I had, in which sv is an invalid pointer (but m_serviceMap is ok)
3100+ //probably caused by the foreach loop in update in the main thread?
3101+ mutex.lock();
3102+ ServiceMap::iterator it = m_serviceMap.find(serviceString);
3103+ if(it!=m_serviceMap.end())
3104+ {
3105+ AbstractAPIService* sv = *it;
3106+ mutex.unlock();
3107+
3108+ //create the response object
3109+ APIServiceResponse apiresponse;
3110+ if(request.getMethod()=="GET")
3111+ {
3112+#ifdef FORCE_THREADED_SERVICES
3113+ apiresponse = sv->get(operation, request.getParameterMap());
3114+#else
3115+ if(sv->supportsThreadedOperation())
3116+ {
3117+ apiresponse = sv->get(operation, request.getParameterMap());
3118+ }
3119+ else
3120+ {
3121+ //invoke it in the main thread!
3122+ QMetaObject::invokeMethod(sv,"get",Qt::BlockingQueuedConnection,
3123+ Q_RETURN_ARG(APIServiceResponse, apiresponse),
3124+ Q_ARG(QByteArray, operation),
3125+ Q_ARG(APIParameters, request.getParameterMap()));
3126+ }
3127+#endif
3128+ apiresponse.applyResponse(&response);
3129+ }
3130+ else if (request.getMethod()=="POST")
3131+ {
3132+#ifdef FORCE_THREADED_SERVICES
3133+ apiresponse = sv->post(operation, request.getParameterMap(), request.getBody());
3134+#else
3135+ if(sv->supportsThreadedOperation())
3136+ {
3137+ apiresponse = sv->post(operation, request.getParameterMap(), request.getBody());
3138+ }
3139+ else
3140+ {
3141+ QMetaObject::invokeMethod(sv,"post",Qt::BlockingQueuedConnection,
3142+ Q_RETURN_ARG(APIServiceResponse, apiresponse),
3143+ Q_ARG(QByteArray, operation),
3144+ Q_ARG(APIParameters, request.getParameterMap()),
3145+ Q_ARG(QByteArray, request.getBody()));
3146+ }
3147+#endif
3148+ apiresponse.applyResponse(&response);
3149+ }
3150+ else
3151+ {
3152+ response.setStatus(405,"Method Not allowed");
3153+ QString str(QStringLiteral("Method %1 not allowed for service %2"));
3154+ response.write(str.arg(QString::fromLatin1(request.getMethod())).arg(QString::fromUtf8(pathWithoutPrefix)).toUtf8(),true);
3155+ }
3156+ }
3157+ else
3158+ {
3159+ mutex.unlock();
3160+ response.setStatus(400,"Bad Request");
3161+ QString str(QStringLiteral("Unknown service: '%1'\n\nAvailable services:\n").arg(QString::fromUtf8(pathWithoutPrefix)));
3162+ for(ServiceMap::iterator it = m_serviceMap.begin();it!=m_serviceMap.end();++it)
3163+ {
3164+ str.append(QString::fromUtf8(it.key()));
3165+ str.append("\n");
3166+ }
3167+ response.write(str.toUtf8(),true);
3168+ }
3169+}
3170
3171=== added file 'plugins/RemoteControl/src/APIController.hpp'
3172--- plugins/RemoteControl/src/APIController.hpp 1970-01-01 00:00:00 +0000
3173+++ plugins/RemoteControl/src/APIController.hpp 2016-06-12 13:59:22 +0000
3174@@ -0,0 +1,64 @@
3175+/*
3176+ * Stellarium Remote Control plugin
3177+ * Copyright (C) 2015 Florian Schaukowitsch
3178+ *
3179+ * This program is free software; you can redistribute it and/or
3180+ * modify it under the terms of the GNU General Public License
3181+ * as published by the Free Software Foundation; either version 2
3182+ * of the License, or (at your option) any later version.
3183+ *
3184+ * This program is distributed in the hope that it will be useful,
3185+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3186+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3187+ * GNU General Public License for more details.
3188+ *
3189+ * You should have received a copy of the GNU General Public License
3190+ * along with this program; if not, write to the Free Software
3191+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
3192+ */
3193+
3194+#ifndef APIHANDLER_HPP_
3195+#define APIHANDLER_HPP_
3196+
3197+#include "httpserver/httprequesthandler.h"
3198+#include "AbstractAPIService.hpp"
3199+
3200+#include <QMutex>
3201+
3202+//! @ingroup remoteControl
3203+//! This class handles the API-specific requests and dispatches them to the correct AbstractAPISerice implementation.
3204+//! Services are registered using registerService().
3205+//! To see the default services used, see the RequestHandler::RequestHandler constructor.
3206+class APIController : public HttpRequestHandler
3207+{
3208+ Q_OBJECT
3209+public:
3210+ //! Constructs an APIController
3211+ //! @param prefixLength Determines how many characters to strip from the front of the request path
3212+ //! @param parent passed on to QObject constructor
3213+ APIController(int prefixLength, QObject* parent = 0);
3214+ virtual ~APIController();
3215+
3216+ //! Should be called each frame from the main thread, like from StelModule::update.
3217+ //! Passed on to each AbstractAPIService::update method for optional processing.
3218+ void update(double deltaTime);
3219+
3220+ //! Handles an API-specific request. It finds out which AbstractAPIService to use
3221+ //! depending on the service name (first part of path until slash). An error is returned for invalid requests.
3222+ //! If a service was found, the request is passed on to its AbstractAPIService::get or AbstractAPIService::post
3223+ //! method depending on the HTTP request type.
3224+ //! If AbstractAPIService::supportsThreadedOperation is false, these methods are called in the Stellarium main thread
3225+ //! using QMetaObject::invokeMethod, otherwise they are directly executed in the current thread (HTTP worker thread).
3226+ virtual void service(HttpRequest& request, HttpResponse& response);
3227+
3228+ //! Registers a service with the APIController.
3229+ //! The AbstractAPIService::serviceName() determines the request path of the service.
3230+ void registerService(AbstractAPIService* service);
3231+private:
3232+ int m_prefixLength;
3233+ typedef QMap<QByteArray,AbstractAPIService*> ServiceMap;
3234+ ServiceMap m_serviceMap;
3235+ QMutex mutex;
3236+};
3237+
3238+#endif
3239
3240=== added file 'plugins/RemoteControl/src/AbstractAPIService.cpp'
3241--- plugins/RemoteControl/src/AbstractAPIService.cpp 1970-01-01 00:00:00 +0000
3242+++ plugins/RemoteControl/src/AbstractAPIService.cpp 2016-06-12 13:59:22 +0000
3243@@ -0,0 +1,159 @@
3244+/*
3245+ * Stellarium Remote Control plugin
3246+ * Copyright (C) 2015 Florian Schaukowitsch
3247+ *
3248+ * This program is free software; you can redistribute it and/or
3249+ * modify it under the terms of the GNU General Public License
3250+ * as published by the Free Software Foundation; either version 2
3251+ * of the License, or (at your option) any later version.
3252+ *
3253+ * This program is distributed in the hope that it will be useful,
3254+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3255+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3256+ * GNU General Public License for more details.
3257+ *
3258+ * You should have received a copy of the GNU General Public License
3259+ * along with this program; if not, write to the Free Software
3260+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
3261+ */
3262+
3263+#include "AbstractAPIService.hpp"
3264+#include <QJsonDocument>
3265+
3266+#include "httpserver/httpresponse.h"
3267+
3268+int APIServiceResponse::metaTypeId = qRegisterMetaType<APIServiceResponse>();
3269+int APIServiceResponse::parametersMetaTypeId = qRegisterMetaType<APIParameters>();
3270+
3271+void APIServiceResponse::setHeader(const QByteArray &name, const QByteArray &val)
3272+{
3273+ headers.insert(name,val);
3274+}
3275+
3276+void APIServiceResponse::setHeader(const QByteArray &name, const int val)
3277+{
3278+ headers.insert(name,QByteArray::number(val));
3279+}
3280+
3281+void APIServiceResponse::setStatus(int status, const QByteArray &text)
3282+{
3283+ this->status = status;
3284+ this->statusText = text;
3285+}
3286+
3287+void APIServiceResponse::applyResponse(HttpResponse *response) const
3288+{
3289+ if(status != -1)
3290+ {
3291+ response->setStatus(status,statusText);
3292+ }
3293+
3294+ //apply headers
3295+ response->getHeaders().unite(headers);
3296+
3297+ //send response data, if any
3298+ if(responseData.isEmpty())
3299+ {
3300+ response->getHeaders().clear();
3301+ response->setStatus(500,"Internal Server Error");
3302+ response->write("Service provided no response",true);
3303+ }
3304+ response->write(responseData,true);
3305+}
3306+
3307+void APIServiceResponse::setData(const QByteArray &data)
3308+{
3309+ this->responseData = data;
3310+}
3311+
3312+void APIServiceResponse::appendData(const QByteArray &data)
3313+{
3314+ this->responseData.append(data);
3315+}
3316+
3317+void APIServiceResponse::writeRequestError(const QByteArray &msg)
3318+{
3319+ setStatus(400,"Bad Request");
3320+ responseData = msg;
3321+}
3322+
3323+void APIServiceResponse::writeJSON(const QJsonDocument &doc)
3324+{
3325+#ifdef QT_NO_DEBUG
3326+ //Use compact JSON format for release builds for smaller files
3327+ QByteArray data = doc.toJson(QJsonDocument::Compact);
3328+#else
3329+ //Use indented JSON format in debug builds for easier human reading
3330+ QByteArray data = doc.toJson(QJsonDocument::Indented);
3331+#endif
3332+ //setHeader("Content-Length",data.size());
3333+ setHeader("Content-Type","application/json; charset=utf-8");
3334+ setData(data);
3335+}
3336+
3337+
3338+void AbstractAPIService::update(double deltaTime)
3339+{
3340+ Q_UNUSED(deltaTime);
3341+}
3342+
3343+bool AbstractAPIService::supportsThreadedOperation() const
3344+{
3345+ return false;
3346+}
3347+
3348+APIServiceResponse AbstractAPIService::get(const QByteArray &operation, const APIParameters &parameters)
3349+{
3350+ APIServiceResponse response;
3351+ getImpl(operation,parameters,response);
3352+ return response;
3353+}
3354+
3355+APIServiceResponse AbstractAPIService::post(const QByteArray &operation, const APIParameters &parameters, const QByteArray &data)
3356+{
3357+ APIServiceResponse response;
3358+ postImpl(operation,parameters,data,response);
3359+ return response;
3360+}
3361+
3362+#ifdef FORCE_THREADED_SERVICES
3363+const Qt::ConnectionType AbstractAPIService::SERVICE_DEFAULT_INVOKETYPE = Qt::BlockingQueuedConnection;
3364+#else
3365+const Qt::ConnectionType AbstractAPIService::SERVICE_DEFAULT_INVOKETYPE = Qt::DirectConnection;
3366+#endif
3367+
3368+void AbstractAPIService::getImpl(const QByteArray& operation, const QMultiMap<QByteArray, QByteArray> &parameters, APIServiceResponse &response)
3369+{
3370+ Q_UNUSED(operation);
3371+ Q_UNUSED(parameters);
3372+
3373+ response.setStatus(405,"Method Not allowed");
3374+ QString str(QStringLiteral("Method GET not allowed for service %2"));
3375+
3376+ response.setData(str.arg(QString::fromLatin1(serviceName())).toLatin1());
3377+}
3378+
3379+void AbstractAPIService::postImpl(const QByteArray& operation, const QMultiMap<QByteArray, QByteArray> &parameters, const QByteArray &data, APIServiceResponse &response)
3380+{
3381+ Q_UNUSED(operation);
3382+ Q_UNUSED(parameters);
3383+ Q_UNUSED(data);
3384+
3385+ response.setStatus(405,"Method Not allowed");
3386+ QString str(QStringLiteral("Method POST not allowed for service %2"));
3387+ response.setData(str.arg(QString::fromLatin1(serviceName())).toLatin1());
3388+}
3389+
3390+
3391+QString AbstractAPIService::wrapHtml(QString &text, const QString &title) const
3392+{
3393+ const QString head = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n"
3394+ "<html><head>\n"
3395+ "<title>" + title + "</title>\n"
3396+ "<link type=\"text/css\" rel=\"stylesheet\" href=\"/iframestyle.css\">\n"
3397+ "<base target=\"_blank\">\n"
3398+ "</head><body>\n";
3399+ const QString tail = "</body></html>";
3400+
3401+ return text.prepend(head).append(tail);
3402+}
3403
3404=== added file 'plugins/RemoteControl/src/AbstractAPIService.hpp'
3405--- plugins/RemoteControl/src/AbstractAPIService.hpp 1970-01-01 00:00:00 +0000
3406+++ plugins/RemoteControl/src/AbstractAPIService.hpp 2016-06-12 13:59:22 +0000
3407@@ -0,0 +1,160 @@
3408+/*
3409+ * Stellarium Remote Control plugin
3410+ * Copyright (C) 2015 Florian Schaukowitsch
3411+ *
3412+ * This program is free software; you can redistribute it and/or
3413+ * modify it under the terms of the GNU General Public License
3414+ * as published by the Free Software Foundation; either version 2
3415+ * of the License, or (at your option) any later version.
3416+ *
3417+ * This program is distributed in the hope that it will be useful,
3418+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3419+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3420+ * GNU General Public License for more details.
3421+ *
3422+ * You should have received a copy of the GNU General Public License
3423+ * along with this program; if not, write to the Free Software
3424+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
3425+ */
3426+
3427+#ifndef ABSTRACTAPISERVICE_HPP_
3428+#define ABSTRACTAPISERVICE_HPP_
3429+
3430+#include <QByteArray>
3431+#include <QMap>
3432+#include <QObject>
3433+
3434+//Uncomment to force each service to run in the HTTP handling threads themselves, like the initial versions
3435+//#define FORCE_THREADED_SERVICES
3436+
3437+class HttpResponse;
3438+class APIController;
3439+
3440+//! \addtogroup remoteControl
3441+//! @{
3442+
3443+//! Thread-safe version of HttpResponse that can be passed around through QMetaObject::invokeMethod.
3444+//! It contains the data that will be sent back to the client in the HTTP thread, when control returns to the APIController.
3445+struct APIServiceResponse
3446+{
3447+public:
3448+ //! Constructs an invalid response
3449+ APIServiceResponse() : status(-1)
3450+ {
3451+
3452+ }
3453+
3454+ //! Sets a specific HTTP header to the specified value
3455+ void setHeader(const QByteArray& name, const QByteArray& val);
3456+ //! Shortcut for int header values
3457+ void setHeader(const QByteArray& name, const int val);
3458+ //! Sets the HTTP status type and status text
3459+ void setStatus(int status, const QByteArray& text);
3460+
3461+ //! Replaces the current return data
3462+ void setData(const QByteArray& data);
3463+ //! Appends to the current return data
3464+ void appendData(const QByteArray& data);
3465+
3466+ //! Sets the HTTP status to 400, and sets the response data to the message
3467+ void writeRequestError(const QByteArray& msg);
3468+ //! Sets the Content-Type to "application/json" and serializes the given document
3469+ //! into JSON text format
3470+ void writeJSON(const QJsonDocument& doc);
3471+
3472+private:
3473+ int status;
3474+ QByteArray statusText;
3475+ QMap<QByteArray,QByteArray> headers;
3476+ QByteArray responseData;
3477+
3478+ //! Applies the data in this APIServiceResponse onto the HttpResponse
3479+ //! Must be called in the HTTP thread, done by APIController
3480+ void applyResponse(HttpResponse* response) const;
3481+
3482+ static int metaTypeId;
3483+ static int parametersMetaTypeId;
3484+ friend class APIController;
3485+
3486+};
3487+
3488+//! Defines the HTTP request parameters for the service
3489+typedef QMultiMap<QByteArray, QByteArray> APIParameters;
3490+
3491+Q_DECLARE_METATYPE(APIServiceResponse)
3492+Q_DECLARE_METATYPE(APIParameters)
3493+
3494+//! Abstract base class for all \ref remoteControl service implementations. Different implementations of this class are mapped to
3495+//! different HTTP request paths. For each API request, the APIController finds out which service to use, and calls its get() or post() method.
3496+class AbstractAPIService : public QObject
3497+{
3498+ Q_OBJECT
3499+public:
3500+ //! Abstract constructor. The service name is used by the APIController for request path mapping.
3501+ AbstractAPIService(const QByteArray& serviceName, QObject* parent = 0) : QObject(parent), m_serviceName(serviceName)
3502+ {
3503+
3504+ }
3505+
3506+ virtual ~AbstractAPIService() { }
3507+
3508+ //! Returns the service name, used for request path mapping by the APIController
3509+ QByteArray serviceName() { return m_serviceName; }
3510+
3511+ //! Return true if the service can safely be run in the HTTP handler thread,
3512+ //! instead of having to queue it into the Stellarium main thread.
3513+ //! Default implementation returns false, i.e. no special threading precautions have to be used
3514+ //! in the get() and post() implementation.
3515+ //! @warning If the macro \c FORCE_THREADED_SERVICES is set, all services will be run
3516+ //! in the HTTP threads for testing, and this method will be ignored.
3517+ virtual bool supportsThreadedOperation() const;
3518+
3519+ //! Called in the main thread each frame. Default implementation does nothing.
3520+ //! Can be used for ongoing actions, for example movement control.
3521+ virtual void update(double deltaTime);
3522+
3523+ //! Wrapper around getImpl(), constructs an APIServiceResponse object for the response and passes it on
3524+ //! @note The thread this is called in depends on the supportThreadedOperation() return value
3525+ Q_INVOKABLE APIServiceResponse get(const QByteArray &operation, const APIParameters &parameters);
3526+ //! Wrapper around postImpl(), constructs an APIServiceResponse object for the response and passes it on
3527+ //! @note The thread this is called in depends on the supportThreadedOperation() return value
3528+ Q_INVOKABLE APIServiceResponse post(const QByteArray &operation, const APIParameters &parameters, const QByteArray& data);
3529+
3530+protected:
3531+ //! Subclasses should implement this to define reactions to HTTP GET requests.
3532+ //! GET requests generally should only query data or program state, and not change it.
3533+ //! If there is an error with the request, use APIServiceResponse::writeRequestError to notify the client.
3534+ //! @param operation The operation string of the request (i.e. the part of the request URL after the service name, without parameters)
3535+ //! @param parameters The extracted service parameters (extracted from the URL)
3536+ //! @param response The response object, write your response into this
3537+ //! @note The thread this is called in depends on the supportThreadedOperation() return value
3538+ virtual void getImpl(const QByteArray& operation, const APIParameters& parameters, APIServiceResponse& response);
3539+ //! Subclasses should implement this to define reactions to HTTP POST requests.
3540+ //! POST requests generally should change data or perform some action.
3541+ //! If there is an error with the request, use APIServiceResponse::writeRequestError to notify the client.
3542+ //! @param operation The operation string of the request (i.e. the part of the request URL after the service name, without parameters)
3543+ //! @param parameters The extracted service parameters (extracted from the URL, and form data, if applicable)
3544+ //! @param data The unmodified data as sent from the client
3545+ //! @param response The response object, write your response into this
3546+ //! @note The thread this is called in depends on the supportThreadedOperation() return value
3547+ virtual void postImpl(const QByteArray& operation, const APIParameters& parameters, const QByteArray& data, APIServiceResponse& response);
3548+
3549+ //! This defines the connection type QMetaObject::invokeMethod has to use inside a service: either Qt::DirectConnection for main thread handling, or
3550+ //! Qt::BlockingQueuedConnection for HTTP thread handling
3551+ static const Qt::ConnectionType SERVICE_DEFAULT_INVOKETYPE;
3552+
3553+ //! Because the HTML descriptions in Stellarium are often not compatible
3554+ //! with "clean" HTML5 which is used for the main interface,
3555+ //! this method can be used to explicitely set the doctype
3556+ //! to 4.01 transitional for better results, and include the stylesheet
3557+ //! \c iframestyle.css
3558+ //! @param text The text to wrap with HTML document tags
3559+ //! @param title The title of the page
3560+ QString wrapHtml(QString& text, const QString& title) const;
3561+private:
3562+ QByteArray m_serviceName;
3563+};
3564+
3565+//! @}
3566+
3567+#endif
3568
3569=== added file 'plugins/RemoteControl/src/CMakeLists.txt'
3570--- plugins/RemoteControl/src/CMakeLists.txt 1970-01-01 00:00:00 +0000
3571+++ plugins/RemoteControl/src/CMakeLists.txt 2016-06-12 13:59:22 +0000
3572@@ -0,0 +1,78 @@
3573+INCLUDE_DIRECTORIES(. gui qtwebapp)
3574+LINK_DIRECTORIES(${BUILD_DIR}/src)
3575+
3576+SET(QtWebApp_SRCS
3577+ qtwebapp/httpserver/httpconnectionhandler.cpp
3578+ qtwebapp/httpserver/httpconnectionhandler.h
3579+ qtwebapp/httpserver/httpconnectionhandlerpool.cpp
3580+ qtwebapp/httpserver/httpconnectionhandlerpool.h
3581+ qtwebapp/httpserver/httpcookie.cpp
3582+ qtwebapp/httpserver/httpcookie.h
3583+ qtwebapp/httpserver/httpglobal.cpp
3584+ qtwebapp/httpserver/httpglobal.h
3585+ qtwebapp/httpserver/httplistener.cpp
3586+ qtwebapp/httpserver/httplistener.h
3587+ qtwebapp/httpserver/httprequest.cpp
3588+ qtwebapp/httpserver/httprequest.h
3589+ qtwebapp/httpserver/httprequesthandler.cpp
3590+ qtwebapp/httpserver/httprequesthandler.h
3591+ qtwebapp/httpserver/httpresponse.cpp
3592+ qtwebapp/httpserver/httpresponse.h
3593+ qtwebapp/httpserver/staticfilecontroller.cpp
3594+ qtwebapp/httpserver/staticfilecontroller.h
3595+
3596+ qtwebapp/templateengine/template.cpp
3597+ qtwebapp/templateengine/template.h
3598+ qtwebapp/templateengine/templateglobal.h
3599+)
3600+
3601+SET(RemoteControl_SRCS
3602+ AbstractAPIService.hpp
3603+ AbstractAPIService.cpp
3604+ APIController.hpp
3605+ APIController.cpp
3606+ MainService.hpp
3607+ MainService.cpp
3608+ ObjectService.hpp
3609+ ObjectService.cpp
3610+ LocationService.hpp
3611+ LocationService.cpp
3612+ LocationSearchService.hpp
3613+ LocationSearchService.cpp
3614+ RemoteControl.hpp
3615+ RemoteControl.cpp
3616+ RequestHandler.hpp
3617+ RequestHandler.cpp
3618+ ScriptService.hpp
3619+ ScriptService.cpp
3620+ SimbadService.hpp
3621+ SimbadService.cpp
3622+ StelActionService.hpp
3623+ StelActionService.cpp
3624+ StelPropertyService.hpp
3625+ StelPropertyService.cpp
3626+ ViewService.hpp
3627+ ViewService.cpp
3628+ gui/RemoteControlDialog.hpp
3629+ gui/RemoteControlDialog.cpp
3630+)
3631+
3632+SET(RemoteControl_UIS
3633+ gui/remoteControlDialog.ui
3634+)
3635+
3636+QT5_WRAP_UI(RemoteControl_UIS_H ${RemoteControl_UIS})
3637+
3638+################# compiles resources files ############
3639+SET(RemoteControl_RES ../RemoteControl.qrc)
3640+QT5_ADD_RESOURCES(RemoteControl_RES_CXX ${RemoteControl_RES})
3641+
3642+SET(extLinkerOption ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${OPENGL_LIBRARIES})
3643+
3644+ADD_LIBRARY(RemoteControl-static STATIC ${RemoteControl_SRCS} ${RemoteControl_RES_CXX} ${RemoteControl_UIS_H} ${QtWebApp_SRCS})
3645+QT5_USE_MODULES(RemoteControl-static Core Network Widgets)
3646+# The library target "RemoteControl-static" has a default OUTPUT_NAME of "RemoteControl-static", so change it.
3647+SET_TARGET_PROPERTIES(RemoteControl-static PROPERTIES OUTPUT_NAME "RemoteControl")
3648+TARGET_LINK_LIBRARIES(RemoteControl-static ${extLinkerOption})
3649+SET_TARGET_PROPERTIES(RemoteControl-static PROPERTIES COMPILE_FLAGS "-DQT_STATICPLUGIN")
3650+ADD_DEPENDENCIES(AllStaticPlugins RemoteControl-static)
3651
3652=== added file 'plugins/RemoteControl/src/LocationSearchService.cpp'
3653--- plugins/RemoteControl/src/LocationSearchService.cpp 1970-01-01 00:00:00 +0000
3654+++ plugins/RemoteControl/src/LocationSearchService.cpp 2016-06-12 13:59:22 +0000
3655@@ -0,0 +1,104 @@
3656+/*
3657+ * Stellarium Remote Control plugin
3658+ * Copyright (C) 2015 Florian Schaukowitsch
3659+ *
3660+ * This program is free software; you can redistribute it and/or
3661+ * modify it under the terms of the GNU General Public License
3662+ * as published by the Free Software Foundation; either version 2
3663+ * of the License, or (at your option) any later version.
3664+ *
3665+ * This program is distributed in the hope that it will be useful,
3666+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3667+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3668+ * GNU General Public License for more details.
3669+ *
3670+ * You should have received a copy of the GNU General Public License
3671+ * along with this program; if not, write to the Free Software
3672+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
3673+ */
3674+
3675+#include "LocationSearchService.hpp"
3676+
3677+#include "StelApp.hpp"
3678+#include "StelCore.hpp"
3679+#include "StelModuleMgr.hpp"
3680+#include "StelLocationMgr.hpp"
3681+
3682+#include <QJsonArray>
3683+#include <QJsonDocument>
3684+#include <QJsonObject>
3685+#include <QRegExp>
3686+
3687+LocationSearchService::LocationSearchService(const QByteArray &serviceName, QObject *parent)
3688+ : AbstractAPIService(serviceName,parent), locMgr(LocationList())
3689+{
3690+ //this is run in the main thread
3691+ connect(&StelApp::getInstance().getLocationMgr(), SIGNAL(locationListChanged()), this, SLOT(mainLocationManagerUpdated()));
3692+ mainLocationManagerUpdated();
3693+}
3694+
3695+void LocationSearchService::mainLocationManagerUpdated()
3696+{
3697+ //this is run in the main thread
3698+ locMgrMutex.lock();
3699+ //copy the contents of the location manager
3700+ locMgr.setLocations(StelApp::getInstance().getLocationMgr().getAll());
3701+ locMgrMutex.unlock();
3702+}
3703+
3704+void LocationSearchService::getImpl(const QByteArray& operation, const APIParameters &parameters, APIServiceResponse &response)
3705+{
3706+ if(operation=="search")
3707+ {
3708+ //parameter must be named "term" to be compatible with jQuery UI autocomplete without further JS code
3709+ QString term = QString::fromUtf8(parameters.value("term"));
3710+
3711+ if(term.isEmpty())
3712+ {
3713+ response.writeRequestError("needs non-empty 'term' parameter");
3714+ return;
3715+ }
3716+
3717+ //the filtering in the app is provided by QSortFilterProxyModel in the view
3718+ //we dont have that luxury, but we make sure the filtering happens in the separate HTTP thread
3719+ locMgrMutex.lock();
3720+ LocationMap allItems = locMgr.getAllMap();
3721+ locMgrMutex.unlock();
3722+
3723+ QJsonArray results;
3724+ const QList<QString>& list = allItems.keys();
3725+
3726+ //use a regexp in wildcard mode, the app does the same
3727+ QRegExp exp(term,Qt::CaseInsensitive, QRegExp::Wildcard);
3728+
3729+ for(QList<QString>::const_iterator it = list.begin();it!=list.end();++it)
3730+ {
3731+ if(it->contains(exp))
3732+ results.append(*it);
3733+ }
3734+
3735+ response.writeJSON(QJsonDocument(results));
3736+ }
3737+ else if(operation=="nearby")
3738+ {
3739+ QString sPlanet = QString::fromUtf8(parameters.value("planet"));
3740+ QString sLatitude = QString::fromUtf8(parameters.value("latitude"));
3741+ QString sLongitude = QString::fromUtf8(parameters.value("longitude"));
3742+ QString sRadius = QString::fromUtf8(parameters.value("radius"));
3743+
3744+ float latitude = sLatitude.toFloat();
3745+ float longitude = sLongitude.toFloat();
3746+ float radius = sRadius.toFloat();
3747+
3748+ locMgrMutex.lock();
3749+ LocationMap results = locMgr.pickLocationsNearby(sPlanet,longitude,latitude,radius);
3750+ locMgrMutex.unlock();
3751+
3752+ response.writeJSON(QJsonDocument(QJsonArray::fromStringList(results.keys())));
3753+ }
3754+ else
3755+ {
3756+ //TODO some sort of service description?
3757+ response.writeRequestError("unsupported operation. GET: search,nearby");
3758+ }
3759+}
3760
3761=== added file 'plugins/RemoteControl/src/LocationSearchService.hpp'
3762--- plugins/RemoteControl/src/LocationSearchService.hpp 1970-01-01 00:00:00 +0000
3763+++ plugins/RemoteControl/src/LocationSearchService.hpp 2016-06-12 13:59:22 +0000
3764@@ -0,0 +1,58 @@
3765+/*
3766+ * Stellarium Remote Control plugin
3767+ * Copyright (C) 2015 Florian Schaukowitsch
3768+ *
3769+ * This program is free software; you can redistribute it and/or
3770+ * modify it under the terms of the GNU General Public License
3771+ * as published by the Free Software Foundation; either version 2
3772+ * of the License, or (at your option) any later version.
3773+ *
3774+ * This program is distributed in the hope that it will be useful,
3775+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3776+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3777+ * GNU General Public License for more details.
3778+ *
3779+ * You should have received a copy of the GNU General Public License
3780+ * along with this program; if not, write to the Free Software
3781+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
3782+ */
3783+
3784+#ifndef LOCATIONSEARCHSERVICE_HPP_
3785+#define LOCATIONSEARCHSERVICE_HPP_
3786+
3787+#include "AbstractAPIService.hpp"
3788+#include "StelLocationMgr.hpp"
3789+#include <QMutex>
3790+
3791+//! @ingroup remoteControl
3792+//! Provides predefined location search functionality, using the StelLocationMgr.
3793+//!
3794+//! @see \ref rcLocationSearchService, LocationService
3795+//! @note This service supports threaded operation
3796+class LocationSearchService : public AbstractAPIService
3797+{
3798+ Q_OBJECT
3799+public:
3800+ LocationSearchService(const QByteArray& serviceName, QObject* parent = 0);
3801+
3802+ virtual ~LocationSearchService() {}
3803+
3804+ //! We work on a copy of the StelLocationMgr, to prevent hitches as the web user is typing
3805+ //! @returns true
3806+ bool supportsThreadedOperation() const Q_DECL_OVERRIDE { return true; }
3807+protected:
3808+ //! @brief Implements the GET method.
3809+ //! @see \ref rcLocationSearchServiceGET
3810+ virtual void getImpl(const QByteArray& operation,const APIParameters& parameters, APIServiceResponse& response) Q_DECL_OVERRIDE;
3811+private slots:
3812+ // connected to the main location manager in the main thread
3813+ void mainLocationManagerUpdated();
3814+private:
3815+ //the location mgr is actually copied to be used in HTTP threads without blocking the main app
3816+ StelLocationMgr locMgr;
3817+ QMutex locMgrMutex;
3818+};
3819+
3820+
3821+
3822+#endif
3823
3824=== added file 'plugins/RemoteControl/src/LocationService.cpp'
3825--- plugins/RemoteControl/src/LocationService.cpp 1970-01-01 00:00:00 +0000
3826+++ plugins/RemoteControl/src/LocationService.cpp 2016-06-12 13:59:22 +0000
3827@@ -0,0 +1,258 @@
3828+/*
3829+ * Stellarium Remote Control plugin
3830+ * Copyright (C) 2015 Florian Schaukowitsch
3831+ *
3832+ * This program is free software; you can redistribute it and/or
3833+ * modify it under the terms of the GNU General Public License
3834+ * as published by the Free Software Foundation; either version 2
3835+ * of the License, or (at your option) any later version.
3836+ *
3837+ * This program is distributed in the hope that it will be useful,
3838+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3839+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3840+ * GNU General Public License for more details.
3841+ *
3842+ * You should have received a copy of the GNU General Public License
3843+ * along with this program; if not, write to the Free Software
3844+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
3845+ */
3846+
3847+#include "LocationService.hpp"
3848+
3849+#include "StelApp.hpp"
3850+#include "StelCore.hpp"
3851+#include "StelFileMgr.hpp"
3852+#include "StelModuleMgr.hpp"
3853+#include "StelLocationMgr.hpp"
3854+#include "StelLocaleMgr.hpp"
3855+#include "StelTranslator.hpp"
3856+#include "SolarSystem.hpp"
3857+
3858+#include <QFileInfo>
3859+#include <QMimeDatabase>
3860+#include <QJsonArray>
3861+#include <QJsonDocument>
3862+#include <QJsonObject>
3863+#include <QStringListModel>
3864+
3865+LocationService::LocationService(const QByteArray &serviceName, QObject *parent) : AbstractAPIService(serviceName,parent)
3866+{
3867+ //this is run in the main thread
3868+ core = StelApp::getInstance().getCore();
3869+ locMgr = &StelApp::getInstance().getLocationMgr();
3870+ ssys = GETSTELMODULE(SolarSystem);
3871+}
3872+
3873+void LocationService::getImpl(const QByteArray& operation, const APIParameters &parameters, APIServiceResponse &response)
3874+{
3875+ if(operation=="list")
3876+ {
3877+ //for now, this does not return location objects (which would require a much larger data transfer), but only the location strings
3878+ //same as in the LocationDialog list
3879+
3880+ //TODO not fully thread safe
3881+ QJsonArray list = QJsonArray::fromStringList(QStringList(locMgr->getAllMap().keys()));
3882+
3883+ response.writeJSON(QJsonDocument(list));
3884+ }
3885+ else if(operation == "countrylist")
3886+ {
3887+ const StelTranslator& trans = *StelTranslator::globalTranslator;
3888+
3889+ QStringList allCountries = StelApp::getInstance().getLocaleMgr().getAllCountryNames();
3890+ QJsonArray list;
3891+ foreach(QString str, allCountries)
3892+ {
3893+ QJsonObject obj;
3894+ obj.insert("name",str);
3895+ obj.insert("name_i18n",trans.qtranslate(str));
3896+ list.append(obj);
3897+ }
3898+
3899+ response.writeJSON(QJsonDocument(list));
3900+ }
3901+ else if(operation == "planetlist")
3902+ {
3903+ const StelTranslator& trans = StelApp::getInstance().getLocaleMgr().getSkyTranslator();
3904+
3905+ QStringList allPlanets = ssys->getAllPlanetEnglishNames();
3906+ QJsonArray list;
3907+ foreach(QString str, allPlanets)
3908+ {
3909+ QJsonObject obj;
3910+ obj.insert("name",str);
3911+ obj.insert("name_i18n",trans.qtranslate(str));
3912+ list.append(obj);
3913+ }
3914+
3915+ response.writeJSON(QJsonDocument(list));
3916+ }
3917+ else if(operation=="planetimage")
3918+ {
3919+ //return the image file for the specified planet
3920+ //logic from LocationDialog
3921+
3922+ QString planet = QString::fromUtf8(parameters.value("planet"));
3923+
3924+ if(planet.isEmpty())
3925+ {
3926+ response.writeRequestError("requires 'planet' parameter");
3927+ return;
3928+ }
3929+
3930+
3931+ SolarSystem* ssm = GETSTELMODULE(SolarSystem);
3932+ PlanetP p = ssm->searchByEnglishName(planet);
3933+ if (p)
3934+ {
3935+ QString path = StelFileMgr::findFile("textures/"+p->getTextMapName());
3936+ QFile file(path);
3937+ if (path.isEmpty() || !file.exists())
3938+ {
3939+ response.setStatus(404,"not found");
3940+ response.setData("planet image not available");
3941+ qWarning() << "ERROR - could not find planet map for " << planet;
3942+ return;
3943+ }
3944+
3945+ QMimeType mime = QMimeDatabase().mimeTypeForFile(path);
3946+
3947+ if(file.open(QIODevice::ReadOnly))
3948+ {
3949+ //allow the image to be cached by browser (1 hour)
3950+ response.setHeader("Cache-Control","max-age="+QByteArray::number(60*60));
3951+ //response.setHeader("Content-Length",static_cast<int>(file.size()));
3952+ if(!mime.isDefault())
3953+ {
3954+ response.setHeader("Content-Type", mime.name().toLatin1());
3955+ }
3956+
3957+ //load and write data
3958+ response.setData(file.readAll());
3959+ }
3960+ else
3961+ {
3962+ response.setStatus(500,"internal server error");
3963+ response.setData("could not open image file");
3964+ }
3965+ }
3966+ else
3967+ {
3968+ response.setStatus(404,"not found");
3969+ response.setData("planet id not found");
3970+ qWarning() << "ERROR - could not find planet " << planet;
3971+ return;
3972+ }
3973+ }
3974+ else
3975+ {
3976+ //TODO some sort of service description?
3977+ response.writeRequestError("unsupported operation. GET: list, countrylist, planetlist, planetimage");
3978+ }
3979+}
3980+
3981+void LocationService::postImpl(const QByteArray& operation, const APIParameters &parameters, const QByteArray &data, APIServiceResponse &response)
3982+{
3983+ Q_UNUSED(data);
3984+
3985+ if (operation == "setlocationfields")
3986+ {
3987+ QString id = QString::fromUtf8(parameters.value("id"));
3988+
3989+ StelLocation loc;
3990+ if(!id.isEmpty())
3991+ {
3992+ //if an id is set, ignore everything else
3993+ //use an invoke here for reasons
3994+ QMetaObject::invokeMethod(locMgr,"locationForString",SERVICE_DEFAULT_INVOKETYPE,
3995+ Q_RETURN_ARG(StelLocation, loc),
3996+ Q_ARG(QString,id));
3997+
3998+ if(loc.isValid())
3999+ {
4000+ //set location
4001+ QMetaObject::invokeMethod(core, "moveObserverTo", SERVICE_DEFAULT_INVOKETYPE,
4002+ Q_ARG(StelLocation, loc),
4003+ Q_ARG(double,0.0) );
4004+
4005+ response.setData("ok");
4006+ return;
4007+ }
4008+ else
4009+ {
4010+ response.writeRequestError("invalid location id");
4011+ return;
4012+ }
4013+ }
4014+
4015+ //copy current loc
4016+ loc = core->getCurrentLocation();
4017+
4018+ //similar to StelScriptMainAPI::setObserverLocation
4019+ QString sLatitude = QString::fromUtf8(parameters.value("latitude"));
4020+ QString sLongitude = QString::fromUtf8(parameters.value("longitude"));
4021+ QString sAltitude = QString::fromUtf8(parameters.value("altitude"));
4022+
4023+ QString name = QString::fromUtf8(parameters.value("name"));
4024+ QString country = QString::fromUtf8(parameters.value("country"));
4025+ QString planet = QString::fromUtf8(parameters.value("planet"));
4026+
4027+ //check each field
4028+ bool doneSomething = false;
4029+ bool ok = false;
4030+ float latitude = sLatitude.toFloat(&ok);
4031+ if(ok && latitude != loc.latitude)
4032+ {
4033+ loc.latitude = latitude;
4034+ doneSomething = true;
4035+ }
4036+ float longitude = sLongitude.toFloat(&ok);
4037+ if(ok && longitude != loc.longitude)
4038+ {
4039+ loc.longitude = longitude;
4040+ doneSomething = true;
4041+ }
4042+ int altitude = sAltitude.toInt(&ok);
4043+ if(ok && altitude != loc.altitude)
4044+ {
4045+ loc.altitude = altitude;
4046+ doneSomething = true;
4047+ }
4048+ if(parameters.contains("name") && name != loc.name)
4049+ {
4050+ loc.name = name;
4051+ doneSomething = true;
4052+ }
4053+ if(!country.isEmpty() && country != loc.country)
4054+ {
4055+ loc.country = country;
4056+ doneSomething = true;
4057+ }
4058+
4059+ if(!planet.isEmpty() && loc.planetName != planet)
4060+ {
4061+ if(ssys->searchByName(planet))
4062+ {
4063+ //set planet
4064+ loc.planetName = planet;
4065+ doneSomething = true;
4066+ }
4067+ }
4068+
4069+ if(doneSomething)
4070+ {
4071+ //update the core
4072+ QMetaObject::invokeMethod(core,"moveObserverTo", SERVICE_DEFAULT_INVOKETYPE,
4073+ Q_ARG(StelLocation, loc),
4074+ Q_ARG(double, 0.0),
4075+ Q_ARG(double, 0.0));
4076+ }
4077+
4078+ response.setData("ok");
4079+ }
4080+ else
4081+ {
4082+ //TODO some sort of service description?
4083+ response.writeRequestError("unsupported operation. POST: setlocation, setlocationfields");
4084+ }
4085+}
4086
4087=== added file 'plugins/RemoteControl/src/LocationService.hpp'
4088--- plugins/RemoteControl/src/LocationService.hpp 1970-01-01 00:00:00 +0000
4089+++ plugins/RemoteControl/src/LocationService.hpp 2016-06-12 13:59:22 +0000
4090@@ -0,0 +1,56 @@
4091+/*
4092+ * Stellarium Remote Control plugin
4093+ * Copyright (C) 2015 Florian Schaukowitsch
4094+ *
4095+ * This program is free software; you can redistribute it and/or
4096+ * modify it under the terms of the GNU General Public License
4097+ * as published by the Free Software Foundation; either version 2
4098+ * of the License, or (at your option) any later version.
4099+ *
4100+ * This program is distributed in the hope that it will be useful,
4101+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4102+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4103+ * GNU General Public License for more details.
4104+ *
4105+ * You should have received a copy of the GNU General Public License
4106+ * along with this program; if not, write to the Free Software
4107+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
4108+ */
4109+
4110+#ifndef LOCATIONSERVICE_HPP_
4111+#define LOCATIONSERVICE_HPP_
4112+
4113+#include "AbstractAPIService.hpp"
4114+
4115+class StelCore;
4116+class StelLocationMgr;
4117+class SolarSystem;
4118+
4119+//! @ingroup remoteControl
4120+//! Provides methods to look up location-related information, and change the current location
4121+//!
4122+//! @see \ref rcLocationService, LocationService
4123+class LocationService : public AbstractAPIService
4124+{
4125+ Q_OBJECT
4126+public:
4127+ LocationService(const QByteArray& serviceName, QObject* parent = 0);
4128+
4129+ virtual ~LocationService() {}
4130+
4131+protected:
4132+ //! @brief Implements the HTTP GET requests
4133+ //! @see \ref rcLocationServiceGET
4134+ virtual void getImpl(const QByteArray& operation,const APIParameters& parameters, APIServiceResponse& response) Q_DECL_OVERRIDE;
4135+ //! @brief Implements the HTTP POST requests
4136+ //! @see \ref rcLocationServicePOST
4137+ virtual void postImpl(const QByteArray &operation, const APIParameters& parameters, const QByteArray &data, APIServiceResponse &response) Q_DECL_OVERRIDE;
4138+private:
4139+ StelCore* core;
4140+ StelLocationMgr* locMgr;
4141+ SolarSystem* ssys;
4142+};
4143+
4144+
4145+
4146+#endif
4147
4148=== added file 'plugins/RemoteControl/src/MainService.cpp'
4149--- plugins/RemoteControl/src/MainService.cpp 1970-01-01 00:00:00 +0000
4150+++ plugins/RemoteControl/src/MainService.cpp 2016-06-12 13:59:22 +0000
4151@@ -0,0 +1,622 @@
4152+/*
4153+ * Stellarium Remote Control plugin
4154+ * Copyright (C) 2015 Florian Schaukowitsch
4155+ *
4156+ * This program is free software; you can redistribute it and/or
4157+ * modify it under the terms of the GNU General Public License
4158+ * as published by the Free Software Foundation; either version 2
4159+ * of the License, or (at your option) any later version.
4160+ *
4161+ * This program is distributed in the hope that it will be useful,
4162+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4163+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4164+ * GNU General Public License for more details.
4165+ *
4166+ * You should have received a copy of the GNU General Public License
4167+ * along with this program; if not, write to the Free Software
4168+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
4169+ */
4170+
4171+#include "MainService.hpp"
4172+
4173+#include "StelApp.hpp"
4174+#include "StelActionMgr.hpp"
4175+#include "StelCore.hpp"
4176+#include "LandscapeMgr.hpp"
4177+#include "StelLocaleMgr.hpp"
4178+#include "StelMainView.hpp"
4179+#include "StelModuleMgr.hpp"
4180+#include "StelMovementMgr.hpp"
4181+#include "StelObjectMgr.hpp"
4182+#include "StelPropertyMgr.hpp"
4183+#include "StelScriptMgr.hpp"
4184+#include "StelSkyCultureMgr.hpp"
4185+#include "StelTranslator.hpp"
4186+#include "StelUtils.hpp"
4187+
4188+#include <QJsonDocument>
4189+
4190+
4191+MainService::MainService(const QByteArray &serviceName, QObject *parent)
4192+ : AbstractAPIService(serviceName,parent),
4193+ moveX(0),moveY(0),lastMoveUpdateTime(0)
4194+{
4195+ //100 should be more than enough
4196+ //this only has to emcompass events that occur between 2 status updates
4197+ actionCache.setCapacity(100);
4198+ propCache.setCapacity(100);
4199+
4200+ //this is run in the main thread
4201+ core = StelApp::getInstance().getCore();
4202+ actionMgr = StelApp::getInstance().getStelActionManager();
4203+ lsMgr = GETSTELMODULE(LandscapeMgr);
4204+ localeMgr = &StelApp::getInstance().getLocaleMgr();
4205+ objMgr = &StelApp::getInstance().getStelObjectMgr();
4206+ mvmgr = GETSTELMODULE(StelMovementMgr);
4207+ propMgr = StelApp::getInstance().getStelPropertyManager();
4208+ scriptMgr = &StelApp::getInstance().getScriptMgr();
4209+ skyCulMgr = &StelApp::getInstance().getSkyCultureMgr();
4210+
4211+ connect(actionMgr,SIGNAL(actionToggled(QString,bool)),this,SLOT(actionToggled(QString,bool)));
4212+ connect(propMgr,SIGNAL(stelPropChanged(QString,QVariant)),this,SLOT(propertyChanged(QString,QVariant)));
4213+
4214+ Q_ASSERT(this->thread()==objMgr->thread());
4215+}
4216+
4217+void MainService::update(double deltaTime)
4218+{
4219+ bool xZero = qFuzzyIsNull(moveX);
4220+ bool yZero = qFuzzyIsNull(moveY);
4221+
4222+ //prevent sudden disconnects from moving endlessly
4223+ if((QDateTime::currentMSecsSinceEpoch() - lastMoveUpdateTime) > 1000)
4224+ {
4225+ if(!xZero || !yZero)
4226+ qDebug()<<"[MainService] move timeout";
4227+ moveX = moveY = .0f;
4228+ }
4229+
4230+ //Similar to StelMovementMgr::updateMotion
4231+
4232+ if(!xZero || !yZero)
4233+ {
4234+ double currentFov = mvmgr->getCurrentFov();
4235+ // the more it is zoomed, the lower the moving speed is (in angle)
4236+ double depl=0.00025*deltaTime*1000*currentFov;
4237+
4238+ float deltaAz = moveX;
4239+ float deltaAlt = moveY;
4240+
4241+ if (deltaAz<0)
4242+ {
4243+ deltaAz = -depl/30;
4244+ if (deltaAz<-0.2)
4245+ deltaAz = -0.2;
4246+ }
4247+ else
4248+ {
4249+ if (deltaAz>0)
4250+ {
4251+ deltaAz = (depl/30);
4252+ if (deltaAz>0.2)
4253+ deltaAz = 0.2;
4254+ }
4255+ }
4256+
4257+ if (deltaAlt<0)
4258+ {
4259+ deltaAlt = -depl/30;
4260+ if (deltaAlt<-0.2)
4261+ deltaAlt = -0.2;
4262+ }
4263+ else
4264+ {
4265+ if (deltaAlt>0)
4266+ {
4267+ deltaAlt = depl/30;
4268+ if (deltaAlt>0.2)
4269+ deltaAlt = 0.2;
4270+ }
4271+ }
4272+
4273+ mvmgr->panView(deltaAz,deltaAlt);
4274+
4275+ //this is required to enable maximal fps for smoothness
4276+ StelMainView::getInstance().thereWasAnEvent();
4277+ }
4278+}
4279+
4280+void MainService::getImpl(const QByteArray& operation, const APIParameters &parameters, APIServiceResponse &response)
4281+{
4282+ if(operation=="status")
4283+ {
4284+ //a listing of the most common stuff that can change often
4285+
4286+ QString sActionId = QString::fromUtf8(parameters.value("actionId"));
4287+ bool actionOk;
4288+ int actionId = sActionId.toInt(&actionOk);
4289+
4290+ QString sPropId = QString::fromUtf8(parameters.value("propId"));
4291+ bool propOk;
4292+ int propId = sPropId.toInt(&propOk);
4293+
4294+ QJsonObject obj;
4295+
4296+ //// Location
4297+ const StelLocation& loc = core->getCurrentLocation();
4298+ {
4299+ QJsonObject obj2;
4300+ obj2.insert("name",loc.name);
4301+ obj2.insert("role",QString(loc.role));
4302+ obj2.insert("planet",loc.planetName);
4303+ obj2.insert("latitude",loc.latitude);
4304+ obj2.insert("longitude",loc.longitude);
4305+ obj2.insert("altitude",loc.altitude);
4306+ obj2.insert("country",loc.country);
4307+ obj2.insert("state",loc.state);
4308+ obj2.insert("landscapeKey",loc.landscapeKey);
4309+ obj.insert("location",obj2);
4310+ }
4311+
4312+ //// Time related stuff
4313+ {
4314+ double jday = core->getJD();
4315+ double deltaT = core->getDeltaT() * StelCore::JD_SECOND;
4316+
4317+ double gmtShift = localeMgr->getGMTShift(jday) / 24.0;
4318+
4319+ QString utcIso = StelUtils::julianDayToISO8601String(jday,true).append('Z');
4320+ QString localIso = StelUtils::julianDayToISO8601String(jday+gmtShift,true);
4321+
4322+ //time zone string
4323+ QString timeZone = localeMgr->getPrintableTimeZoneLocal(jday);
4324+
4325+ QJsonObject obj2;
4326+ obj2.insert("jday",jday);
4327+ obj2.insert("deltaT",deltaT);
4328+ obj2.insert("gmtShift",gmtShift);
4329+ obj2.insert("timeZone",timeZone);
4330+ obj2.insert("utc",utcIso);
4331+ obj2.insert("local",localIso);
4332+ obj2.insert("isTimeNow",core->getIsTimeNow());
4333+ obj2.insert("timerate",core->getTimeRate());
4334+ obj.insert("time",obj2);
4335+ }
4336+
4337+ //// Info about selected object (only primary)
4338+ {
4339+ QString infoStr;
4340+ QMetaObject::invokeMethod(this,"getInfoString",SERVICE_DEFAULT_INVOKETYPE,
4341+ Q_RETURN_ARG(QString,infoStr));
4342+ obj.insert("selectioninfo",infoStr);
4343+ }
4344+
4345+ //// Info about current view
4346+ {
4347+ QJsonObject obj2;
4348+
4349+ // the aim fov may lie outside the min/max bounds, so constrain it
4350+ double fov = mvmgr->getAimFov();
4351+ if(fov < mvmgr->getMinFov())
4352+ fov = mvmgr->getMinFov();
4353+ else if (fov>mvmgr->getMaxFov())
4354+ fov = mvmgr->getMaxFov();
4355+
4356+ obj2.insert("fov",fov);
4357+
4358+ obj.insert("view",obj2);
4359+ }
4360+
4361+ //// Info about changed actions & props (if requested)
4362+ {
4363+ if(actionOk)
4364+ obj.insert("actionChanges",getActionChangesSinceID(actionId));
4365+ if(propOk)
4366+ obj.insert("propertyChanges",getPropertyChangesSinceID(propId));
4367+ }
4368+
4369+ response.writeJSON(QJsonDocument(obj));
4370+ }
4371+ else if(operation=="plugins")
4372+ {
4373+ // Retrieve list of plugins
4374+
4375+ QJsonObject mainObj;
4376+
4377+ StelModuleMgr& modMgr = StelApp::getInstance().getModuleMgr();
4378+ foreach(const StelModuleMgr::PluginDescriptor& desc, modMgr.getPluginsList())
4379+ {
4380+ QJsonObject pluginObj,infoObj;
4381+ pluginObj.insert("loadAtStartup", desc.loadAtStartup);
4382+ pluginObj.insert("loaded", desc.loaded);
4383+
4384+ infoObj.insert("authors", desc.info.authors);
4385+ infoObj.insert("contact", desc.info.contact);
4386+ infoObj.insert("description", desc.info.description);
4387+ infoObj.insert("displayedName", desc.info.displayedName);
4388+ infoObj.insert("startByDefault", desc.info.startByDefault);
4389+ infoObj.insert("version", desc.info.version);
4390+
4391+ pluginObj.insert("info",infoObj);
4392+ mainObj.insert(desc.info.id, pluginObj);
4393+ }
4394+
4395+ response.writeJSON(QJsonDocument(mainObj));
4396+ }
4397+ else
4398+ {
4399+ //TODO some sort of service description?
4400+ response.writeRequestError("unsupported operation. GET: status, plugins");
4401+ }
4402+}
4403+
4404+void MainService::postImpl(const QByteArray& operation, const APIParameters &parameters, const QByteArray &data, APIServiceResponse &response)
4405+{
4406+ Q_UNUSED(data);
4407+
4408+ if(operation == "time")
4409+ {
4410+ bool doneSomething = false;
4411+ bool ok;
4412+
4413+ //set the time + timerate
4414+ {
4415+ const QByteArray& raw = parameters.value("time");
4416+ if(!raw.isEmpty())
4417+ {
4418+ //parse time and set it
4419+ double jday = QString(raw).toDouble(&ok);
4420+ if(ok)
4421+ {
4422+ //check for invalid double (NaN, inf...)
4423+ //this will crash the app if it is allowed
4424+ if(qIsNaN(jday) || qIsInf(jday))
4425+ {
4426+ qWarning()<<"[RemoteControl] Prevented setting invalid time"<<jday<<", does the web interface have a bug?";
4427+ response.setData("error: invalid time value");
4428+ return;
4429+ }
4430+
4431+ doneSomething = true;
4432+ //set new time
4433+ QMetaObject::invokeMethod(core,"setJD", SERVICE_DEFAULT_INVOKETYPE,
4434+ Q_ARG(double,jday));
4435+ }
4436+ }
4437+ }
4438+ {
4439+ const QByteArray& raw = parameters.value("timerate");
4440+ if(!raw.isEmpty())
4441+ {
4442+ //parse timerate and set it
4443+ double rate = QString(raw).toDouble(&ok);
4444+ if(ok)
4445+ {
4446+ doneSomething = true;
4447+ //set new time rate
4448+ QMetaObject::invokeMethod(core,"setTimeRate", SERVICE_DEFAULT_INVOKETYPE,
4449+ Q_ARG(double,rate));
4450+ }
4451+ }
4452+ }
4453+
4454+ if(doneSomething)
4455+ response.setData("ok");
4456+ else
4457+ response.setData("error: invalid parameters, use time/timerate as double values");
4458+ }
4459+ else if(operation == "focus")
4460+ {
4461+ QString target = QString::fromUtf8(parameters.value("target"));
4462+
4463+ //check target string first
4464+ if(target.isEmpty())
4465+ {
4466+ if(parameters.value("position").isEmpty())
4467+ {
4468+ //no parameters = clear focus
4469+ target = "";
4470+ }
4471+ else
4472+ {
4473+ //parse position
4474+ QJsonDocument doc = QJsonDocument::fromJson(parameters.value("position"));
4475+ QJsonArray arr = doc.array();
4476+ if(arr.size() == 3)
4477+ {
4478+ Vec3d pos;
4479+ pos[0] = arr.at(0).toDouble();
4480+ pos[1] = arr.at(1).toDouble();
4481+ pos[2] = arr.at(2).toDouble();
4482+
4483+ //deselect and move
4484+ QMetaObject::invokeMethod(this,"focusPosition", SERVICE_DEFAULT_INVOKETYPE,
4485+ Q_ARG(Vec3d,pos));
4486+ response.setData("ok");
4487+ return;
4488+ }
4489+
4490+ response.writeRequestError("invalid position format");
4491+ return;
4492+ }
4493+ }
4494+
4495+ bool result;
4496+ QMetaObject::invokeMethod(this,"focusObject",SERVICE_DEFAULT_INVOKETYPE,
4497+ Q_RETURN_ARG(bool,result),
4498+ Q_ARG(QString,target));
4499+
4500+ response.setData(result ? "true" : "false");
4501+ }
4502+ else if(operation == "move")
4503+ {
4504+ QString xs = QString::fromUtf8(parameters.value("x"));
4505+ QString ys = QString::fromUtf8(parameters.value("y"));
4506+
4507+ bool xOk,yOk;
4508+ float x = xs.toInt(&xOk);
4509+ float y = ys.toInt(&yOk);
4510+
4511+ if(xOk || yOk)
4512+ {
4513+ QMetaObject::invokeMethod(this,"updateMovement", SERVICE_DEFAULT_INVOKETYPE,
4514+ Q_ARG(float,x),
4515+ Q_ARG(float,y),
4516+ Q_ARG(bool,xOk),
4517+ Q_ARG(bool,yOk));
4518+
4519+ response.setData("ok");
4520+ }
4521+ else
4522+ response.writeRequestError("requires x or y parameter");
4523+ }
4524+ else if (operation == "fov")
4525+ {
4526+ QString fov = QString::fromUtf8(parameters.value("fov"));
4527+ bool ok;
4528+ double dFov = fov.toDouble(&ok);
4529+
4530+ if(fov.isEmpty() || !ok)
4531+ {
4532+ response.writeRequestError("requires fov parameter");
4533+ return;
4534+ }
4535+
4536+ QMetaObject::invokeMethod(this,"setFov",SERVICE_DEFAULT_INVOKETYPE,
4537+ Q_ARG(double,dFov));
4538+
4539+ response.setData("ok");
4540+ }
4541+ else
4542+ {
4543+ //TODO some sort of service description?
4544+ response.writeRequestError("unsupported operation. POST: time,focus,move,fov");
4545+ }
4546+}
4547+
4548+StelObjectP MainService::getSelectedObject()
4549+{
4550+ const QList<StelObjectP>& list = objMgr->getSelectedObject();
4551+ if(list.isEmpty())
4552+ return StelObjectP();
4553+ return list.first();
4554+}
4555+
4556+QString MainService::getInfoString()
4557+{
4558+ StelObjectP selectedObject = getSelectedObject();
4559+ if(selectedObject.isNull())
4560+ return QString();
4561+ return selectedObject->getInfoString(core,StelObject::AllInfo | StelObject::NoFont);
4562+}
4563+
4564+bool MainService::focusObject(const QString &name)
4565+{
4566+ //StelDialog::gotoObject
4567+
4568+ //if name is empty, unselect
4569+ if(name.isEmpty())
4570+ {
4571+ objMgr->unSelect();
4572+ return true;
4573+ }
4574+
4575+ bool result = false;
4576+ if (objMgr->findAndSelectI18n(name) || objMgr->findAndSelect(name))
4577+ {
4578+ const QList<StelObjectP> newSelected = objMgr->getSelectedObject();
4579+ if (!newSelected.empty())
4580+ {
4581+ // Can't point to home planet
4582+ if (newSelected[0]->getEnglishName()!=core->getCurrentLocation().planetName)
4583+ {
4584+ mvmgr->moveToObject(newSelected[0], mvmgr->getAutoMoveDuration());
4585+ mvmgr->setFlagTracking(true);
4586+ result = true;
4587+ }
4588+ else
4589+ {
4590+ objMgr->unSelect();
4591+ }
4592+ }
4593+ }
4594+ return result;
4595+}
4596+
4597+void MainService::focusPosition(const Vec3d &pos)
4598+{
4599+ objMgr->unSelect();
4600+ mvmgr->moveToJ2000(pos, mvmgr->getAutoMoveDuration());
4601+}
4602+
4603+void MainService::updateMovement(float x, float y, bool xUpdated, bool yUpdated)
4604+{
4605+ if(xUpdated)
4606+ {
4607+ this->moveX = x;
4608+ }
4609+ if(yUpdated)
4610+ {
4611+ this->moveY = y;
4612+ }
4613+ qint64 curTime = QDateTime::currentMSecsSinceEpoch();
4614+ //qDebug()<<"updateMove"<<x<<y<<(curTime-lastMoveUpdateTime);
4615+ lastMoveUpdateTime = curTime;
4616+}
4617+
4618+void MainService::setFov(double fov)
4619+{
4620+ //TODO calculate a better move duration here
4621+ mvmgr->zoomTo(fov,0.25f);
4622+}
4623+
4624+void MainService::actionToggled(const QString &id, bool val)
4625+{
4626+ actionMutex.lock();
4627+ actionCache.append(ActionCacheEntry(id,val));
4628+ if(!actionCache.areIndexesValid())
4629+ {
4630+ //in theory, this can happen, but practically not so much
4631+ qWarning()<<"Action cache indices invalid";
4632+ actionCache.clear();
4633+ }
4634+ actionMutex.unlock();
4635+}
4636+
4637+void MainService::propertyChanged(const QString &id, const QVariant &val)
4638+{
4639+ propMutex.lock();
4640+ propCache.append(PropertyCacheEntry(id,val));
4641+ if(!propCache.areIndexesValid())
4642+ {
4643+ //in theory, this can happen, but practically not so much
4644+ qWarning()<<"Property cache indices invalid";
4645+ propCache.clear();
4646+ }
4647+ propMutex.unlock();
4648+}
4649+
4650+QJsonObject MainService::getActionChangesSinceID(int changeId)
4651+{
4652+ //changeId is the last id the interface is available
4653+ //or -2 if the interface just started
4654+ // -1 means the initial state was set
4655+
4656+ QJsonObject obj;
4657+ QJsonObject changes;
4658+ int newId = changeId;
4659+
4660+
4661+ actionMutex.lock();
4662+ if(actionCache.isEmpty())
4663+ {
4664+ if(changeId!=-1)
4665+ {
4666+ //this is either the initial state (-2) or
4667+ //something is "broken", probably from an existing web interface that reconnected after restart
4668+ //force a full reload
4669+
4670+ foreach(StelAction* ac, actionMgr->getActionList())
4671+ {
4672+ if(ac->isCheckable())
4673+ {
4674+ changes.insert(ac->getId(),ac->isChecked());
4675+ }
4676+ }
4677+ newId = -1;
4678+ }
4679+ }
4680+ else
4681+ {
4682+ if(changeId > actionCache.lastIndex() || changeId < (actionCache.firstIndex()-1))
4683+ {
4684+ //this is either the initial state (-2) or
4685+ //"broken" state again, force full reload
4686+ foreach(StelAction* ac, actionMgr->getActionList())
4687+ {
4688+ if(ac->isCheckable())
4689+ {
4690+ changes.insert(ac->getId(),ac->isChecked());
4691+ }
4692+ }
4693+ newId = actionCache.lastIndex();
4694+ }
4695+ else if(changeId < actionCache.lastIndex())
4696+ {
4697+ //create a "diff" between changeId to lastIndex
4698+ for(int i = changeId+1;i<=actionCache.lastIndex();++i)
4699+ {
4700+ const ActionCacheEntry& e = actionCache.at(i);
4701+ changes.insert(e.action,e.val);
4702+ }
4703+ newId = actionCache.lastIndex();
4704+ }
4705+ //else no changes happened, interface is at current state!
4706+ }
4707+ actionMutex.unlock();
4708+
4709+ obj.insert("changes",changes);
4710+ obj.insert("id",newId);
4711+
4712+ return obj;
4713+}
4714+
4715+QJsonObject MainService::getPropertyChangesSinceID(int changeId)
4716+{
4717+ //changeId is the last id the interface is available
4718+ //or -2 if the interface just started
4719+ // -1 means the initial state was set
4720+ QJsonObject obj;
4721+ QJsonObject changes;
4722+ int newId = changeId;
4723+
4724+ propMutex.lock();
4725+ if(propCache.isEmpty())
4726+ {
4727+ if(changeId!=-1)
4728+ {
4729+ //this is either the initial state (-2) or
4730+ //something is "broken", probably from an existing web interface that reconnected after restart
4731+ //force a full reload
4732+ const StelPropertyMgr::StelPropertyMap& map = propMgr->getPropertyMap();
4733+ for(StelPropertyMgr::StelPropertyMap::const_iterator it = map.constBegin();
4734+ it!=map.constEnd();++it)
4735+ {
4736+ changes.insert(it.key(), QJsonValue::fromVariant((*it)->getValue()));
4737+ }
4738+ newId = -1;
4739+ }
4740+ }
4741+ else
4742+ {
4743+ if(changeId > propCache.lastIndex() || changeId < (propCache.firstIndex()-1))
4744+ {
4745+ //this is either the initial state (-2) or
4746+ //"broken" state again, force full reload
4747+ const StelPropertyMgr::StelPropertyMap& map = propMgr->getPropertyMap();
4748+ for(StelPropertyMgr::StelPropertyMap::const_iterator it = map.constBegin();
4749+ it!=map.constEnd();++it)
4750+ {
4751+ changes.insert(it.key(), QJsonValue::fromVariant((*it)->getValue()));
4752+ }
4753+ newId = propCache.lastIndex();
4754+ }
4755+ else if(changeId < propCache.lastIndex())
4756+ {
4757+ //create a "diff" between changeId to lastIndex
4758+ for(int i = changeId+1;i<=propCache.lastIndex();++i)
4759+ {
4760+ const PropertyCacheEntry& e = propCache.at(i);
4761+ changes.insert(e.id,QJsonValue::fromVariant(e.val));
4762+ }
4763+ newId = propCache.lastIndex();
4764+ }
4765+ //else no changes happened, interface is at current state!
4766+ }
4767+ propMutex.unlock();
4768+
4769+ obj.insert("changes",changes);
4770+ obj.insert("id",newId);
4771+
4772+ return obj;
4773+}
4774
4775=== added file 'plugins/RemoteControl/src/MainService.hpp'
4776--- plugins/RemoteControl/src/MainService.hpp 1970-01-01 00:00:00 +0000
4777+++ plugins/RemoteControl/src/MainService.hpp 2016-06-12 13:59:22 +0000
4778@@ -0,0 +1,122 @@
4779+/*
4780+ * Stellarium Remote Control plugin
4781+ * Copyright (C) 2015 Florian Schaukowitsch
4782+ *
4783+ * This program is free software; you can redistribute it and/or
4784+ * modify it under the terms of the GNU General Public License
4785+ * as published by the Free Software Foundation; either version 2
4786+ * of the License, or (at your option) any later version.
4787+ *
4788+ * This program is distributed in the hope that it will be useful,
4789+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4790+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4791+ * GNU General Public License for more details.
4792+ *
4793+ * You should have received a copy of the GNU General Public License
4794+ * along with this program; if not, write to the Free Software
4795+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
4796+ */
4797+
4798+#ifndef MAINSERVICE_HPP_
4799+#define MAINSERVICE_HPP_
4800+
4801+#include "AbstractAPIService.hpp"
4802+
4803+#include "StelObjectType.hpp"
4804+#include "VecMath.hpp"
4805+
4806+#include <QContiguousCache>
4807+#include <QJsonObject>
4808+#include <QMutex>
4809+
4810+class StelCore;
4811+class StelActionMgr;
4812+class LandscapeMgr;
4813+class StelLocaleMgr;
4814+class StelMovementMgr;
4815+class StelObjectMgr;
4816+class StelPropertyMgr;
4817+class StelScriptMgr;
4818+class StelSkyCultureMgr;
4819+
4820+//! @ingroup remoteControl
4821+//! Implements the main API services, including the \c status operation which can be repeatedly polled to find the current state of the main program,
4822+//! including time, view, location, StelAction and StelProperty state changes, movement, script status ...
4823+//!
4824+//! @see @ref rcMainService
4825+class MainService : public AbstractAPIService
4826+{
4827+ Q_OBJECT
4828+public:
4829+ MainService(const QByteArray& serviceName, QObject* parent = 0);
4830+
4831+ virtual ~MainService() {}
4832+
4833+ //! Used to implement move functionality
4834+ virtual void update(double deltaTime) Q_DECL_OVERRIDE;
4835+
4836+protected:
4837+ //! @brief Implements the GET operations
4838+ //! @see @ref rcMainServiceGET
4839+ virtual void getImpl(const QByteArray& operation,const APIParameters &parameters, APIServiceResponse& response) Q_DECL_OVERRIDE;
4840+ //! @brief Implements the HTTP POST operations
4841+ //! @see @ref rcMainServicePOST
4842+ virtual void postImpl(const QByteArray &operation, const APIParameters &parameters, const QByteArray &data, APIServiceResponse &response) Q_DECL_OVERRIDE;
4843+
4844+private slots:
4845+ StelObjectP getSelectedObject();
4846+
4847+ //! Returns the info string of the currently selected object
4848+ QString getInfoString();
4849+
4850+ //! Like StelDialog::gotoObject
4851+ bool focusObject(const QString& name);
4852+ void focusPosition(const Vec3d& pos);
4853+
4854+ void updateMovement(float x, float y, bool xUpdated, bool yUpdated);
4855+ void setFov(double fov);
4856+
4857+ void actionToggled(const QString& id, bool val);
4858+ void propertyChanged(const QString& id, const QVariant& val);
4859+
4860+private:
4861+ StelCore* core;
4862+ StelActionMgr* actionMgr;
4863+ LandscapeMgr* lsMgr;
4864+ StelLocaleMgr* localeMgr;
4865+ StelMovementMgr* mvmgr;
4866+ StelObjectMgr* objMgr;
4867+ StelPropertyMgr* propMgr;
4868+ StelScriptMgr* scriptMgr;
4869+ StelSkyCultureMgr* skyCulMgr;
4870+
4871+ float moveX,moveY;
4872+ qint64 lastMoveUpdateTime;
4873+
4874+ struct ActionCacheEntry
4875+ {
4876+ ActionCacheEntry(const QString& str,bool val) : action(str),val(val) {}
4877+ QString action;
4878+ bool val;
4879+ };
4880+
4881+ //lists the recently toggled actions - this is a pseudo-circular buffer
4882+ QContiguousCache<ActionCacheEntry> actionCache;
4883+ QMutex actionMutex;
4884+ QJsonObject getActionChangesSinceID(int changeId);
4885+
4886+ struct PropertyCacheEntry
4887+ {
4888+ PropertyCacheEntry(const QString& str, const QVariant& val) : id(str),val(val) {}
4889+ QString id;
4890+ QVariant val;
4891+ };
4892+ QContiguousCache<PropertyCacheEntry> propCache;
4893+ QMutex propMutex;
4894+ QJsonObject getPropertyChangesSinceID(int changeId);
4895+
4896+};
4897+
4898+
4899+
4900+#endif
4901
4902=== added file 'plugins/RemoteControl/src/ObjectService.cpp'
4903--- plugins/RemoteControl/src/ObjectService.cpp 1970-01-01 00:00:00 +0000
4904+++ plugins/RemoteControl/src/ObjectService.cpp 2016-06-12 13:59:22 +0000
4905@@ -0,0 +1,216 @@
4906+/*
4907+ * Stellarium Remote Control plugin
4908+ * Copyright (C) 2015 Florian Schaukowitsch
4909+ *
4910+ * This program is free software; you can redistribute it and/or
4911+ * modify it under the terms of the GNU General Public License
4912+ * as published by the Free Software Foundation; either version 2
4913+ * of the License, or (at your option) any later version.
4914+ *
4915+ * This program is distributed in the hope that it will be useful,
4916+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4917+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4918+ * GNU General Public License for more details.
4919+ *
4920+ * You should have received a copy of the GNU General Public License
4921+ * along with this program; if not, write to the Free Software
4922+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
4923+ */
4924+
4925+#include "ObjectService.hpp"
4926+
4927+#include "SearchDialog.hpp"
4928+#include "StelApp.hpp"
4929+#include "StelCore.hpp"
4930+#include "StelObjectMgr.hpp"
4931+#include "StelTranslator.hpp"
4932+
4933+#include <QEventLoop>
4934+#include <QJsonArray>
4935+#include <QJsonDocument>
4936+#include <QJsonObject>
4937+#include <QSettings>
4938+#include <QMutex>
4939+#include <QThreadPool>
4940+#include <QRunnable>
4941+#include <QWaitCondition>
4942+
4943+ObjectService::ObjectService(const QByteArray &serviceName, QObject *parent) : AbstractAPIService(serviceName,parent)
4944+{
4945+ //this is run in the main thread
4946+ core = StelApp::getInstance().getCore();
4947+ objMgr = &StelApp::getInstance().getStelObjectMgr();
4948+ useStartOfWords = StelApp::getInstance().getSettings()->value("search/flag_start_words", false).toBool();
4949+}
4950+
4951+QStringList ObjectService::performSearch(const QString &text)
4952+{
4953+ //perform substitution greek text --> symbol
4954+ QString greekText = substituteGreek(text);
4955+
4956+ QStringList matches;
4957+ if(greekText != text) {
4958+ matches = objMgr->listMatchingObjectsI18n(text, 3, useStartOfWords);
4959+ matches += objMgr->listMatchingObjects(text, 3, useStartOfWords);
4960+ matches += objMgr->listMatchingObjectsI18n(greekText, (8 - matches.size()), useStartOfWords);
4961+ } else {
4962+ //no greek replaced, saves 1 call
4963+ matches = objMgr->listMatchingObjectsI18n(text, 5, useStartOfWords);
4964+ matches += objMgr->listMatchingObjects(text, 5, useStartOfWords);
4965+ }
4966+
4967+ return matches;
4968+}
4969+
4970+QString ObjectService::substituteGreek(const QString &text)
4971+{
4972+ //use the searchdialog static method for that
4973+ return SearchDialog::substituteGreek(text);
4974+}
4975+
4976+void ObjectService::getImpl(const QByteArray& operation, const APIParameters &parameters, APIServiceResponse &response)
4977+{
4978+ //make sure the object still "lives" in the main Stel thread, even though
4979+ //we may currently be in the HTTP thread
4980+ Q_ASSERT(this->thread() == objMgr->thread());
4981+
4982+ if(operation=="find")
4983+ {
4984+ //this may contain greek or other unicode letters
4985+ QString str = QString::fromUtf8(parameters.value("str"));
4986+ str = str.trimmed().toLower();
4987+
4988+ if(str.isEmpty())
4989+ {
4990+ response.writeRequestError("empty search string");
4991+ return;
4992+ }
4993+
4994+ //qDebug()<<"Search string"<<str;
4995+
4996+ QStringList results;
4997+ QMetaObject::invokeMethod(this,"performSearch",SERVICE_DEFAULT_INVOKETYPE,
4998+ Q_RETURN_ARG(QStringList,results),
4999+ Q_ARG(QString,str));
5000+
The diff has been truncated for viewing.