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

Proposed by gzotti
Status: Superseded
Proposed branch: lp:~registry/stellarium/socis2015
Merge into: lp:stellarium
Diff against target: 72688 lines (+65902/-1757) (has conflicts)
238 files modified
CMakeLists.txt (+31/-6)
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/-83)
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/ChangeLog (+3/-0)
plugins/RemoteControl/README (+47/-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 (+123/-0)
po/stellarium-remotecontrol/stellarium-remotecontrol.pot (+581/-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 (+26/-16)
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)
Text conflict in CMakeLists.txt
To merge this branch: bzr merge lp:~registry/stellarium/socis2015
Reviewer Review Type Date Requested Status
gzotti Needs Resubmitting
Fabien Chéreau Needs Fixing
Review via email: mp+294410@code.launchpad.net

This proposal has been superseded by a proposal from 2016-06-04.

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 :

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 :
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 :
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...

lp:~registry/stellarium/socis2015 updated
7776. By Florian Schaukowitsch

Move RemoteControl webroot into plugin folder
The installation is done in a webroot folder in the install root directory, and can be overridden by a webroot folder in the Stellarium user root directory

7777. By gzotti

slightly enlarged time spinner buttons (better to touch)

7778. By Alexander Wolf

changed the naming of configure options (avoid inconsistency to other configure options); auto start of Remote Control plugin was disabled for security reasons

7779. By Florian Schaukowitsch

StelPropertyMgr can now register all properties of a QObject automatically, with the ID of the StelProperty following the format "<objectName>.<propertyName>", like QtScript uses for property access
All StelModules which are registered with the StelModuleMgr are also automatically registered with the StelPropertyMgr
Added an alternative way to get/set StelProperty values directly with the string ID, without retrieving the StelProperty object first
Removed all StelPropertyMgr::registerProperty calls from StelModules and core classes, it is still being used to register StelActions as StelProperty
Renamed all property accesses to use the new format
Made StelPropery management more efficient by using QMap instead of relying on QObject parent/child relationship

7780. By Florian Schaukowitsch

Removed support for boolean slots from StelAction to simplify the code and make the usage cases clearer
Modified Oculars plugin to use Q_PROPERTY instead of boolean slots for StelAction, this seems to be the only place where this functionality was actually used
StelAction now always uses a StelProperty when connected to a bool property because StelProperty now supports arbitrary properties
Fixed some whitespace issues

Revision history for this message
Florian Schaukowitsch (fschauk) wrote :

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 :

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

7783. By gzotti

removed useless files

7784. By Alexander Wolf

sync with trunk; avoid conflicts

7785. By Alexander Wolf

added changes for Miller projection

Unmerged revisions

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