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

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

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

Commit message

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

Description of the change

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

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

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

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

Hi Florian, Georg,

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

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

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

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

Hello Fabien,
thanks for the kind words!

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

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

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

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

Read more...

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

Hi,

see me replies inline

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

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

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

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

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

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

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

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

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

Read more...

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

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

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

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

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

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

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

Looks very good IMHO, thank you!
Fabien?

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

A small fix for translations support

7782. By Alexander Wolf

A small fix for cmake

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

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

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

removed useless files

7784. By Alexander Wolf

sync with trunk; avoid conflicts

7785. By Alexander Wolf

added changes for Miller projection

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

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

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2016-06-05 07:56:01 +0000
+++ CMakeLists.txt 2016-06-12 13:59:22 +0000
@@ -18,9 +18,15 @@
1818
19########### Project name ###########19########### Project name ###########
20PROJECT(Stellarium)20PROJECT(Stellarium)
21SET(STELLARIUM_MAJOR "0")21# Use integer versions instead of strings for easier handling if required
22SET(STELLARIUM_MINOR "14")22SET(STELLARIUM_MAJOR 0)
23SET(STELLARIUM_PATCH "90")23SET(STELLARIUM_MINOR 14)
24SET(STELLARIUM_PATCH 90)
25ADD_DEFINITIONS(
26-DSTELLARIUM_MAJOR=${STELLARIUM_MAJOR}
27-DSTELLARIUM_MINOR=${STELLARIUM_MINOR}
28-DSTELLARIUM_PATCH=${STELLARIUM_PATCH}
29)
24SET(VERSION "${STELLARIUM_MAJOR}.${STELLARIUM_MINOR}.${STELLARIUM_PATCH}")30SET(VERSION "${STELLARIUM_MAJOR}.${STELLARIUM_MINOR}.${STELLARIUM_PATCH}")
25SET(PACKAGE stellarium)31SET(PACKAGE stellarium)
26SET(COPYRIGHT_YEARS "2000-2016")32SET(COPYRIGHT_YEARS "2000-2016")
@@ -174,7 +180,7 @@
174SET(STELLARIUM_PLUGINS) # Global list of all the plugins.180SET(STELLARIUM_PLUGINS) # Global list of all the plugins.
175MACRO(ADD_PLUGIN NAME DEFAULT)181MACRO(ADD_PLUGIN NAME DEFAULT)
176 STRING(TOUPPER ${NAME} NAME_UP)182 STRING(TOUPPER ${NAME} NAME_UP)
177 SET(USE_PLUGIN_${NAME_UP} ${DEFAULT} CACHE BOOL "Define wheter the ${NAME} plugin should be created.")183 SET(USE_PLUGIN_${NAME_UP} ${DEFAULT} CACHE BOOL "Define whether the ${NAME} plugin should be created.")
178 SET(STELLARIUM_PLUGINS ${STELLARIUM_PLUGINS} ${NAME})184 SET(STELLARIUM_PLUGINS ${STELLARIUM_PLUGINS} ${NAME})
179ENDMACRO()185ENDMACRO()
180186
@@ -197,6 +203,9 @@
197ADD_PLUGIN(PointerCoordinates 1)203ADD_PLUGIN(PointerCoordinates 1)
198ADD_PLUGIN(Pulsars 1)204ADD_PLUGIN(Pulsars 1)
199ADD_PLUGIN(Quasars 1)205ADD_PLUGIN(Quasars 1)
206# SOCIS 2015:
207ADD_PLUGIN(RemoteControl 1)
208ADD_PLUGIN(RemoteSync 0)
200ADD_PLUGIN(Satellites 1)209ADD_PLUGIN(Satellites 1)
201ADD_PLUGIN(Scenery3d 1)210ADD_PLUGIN(Scenery3d 1)
202ADD_PLUGIN(SolarSystemEditor 1)211ADD_PLUGIN(SolarSystemEditor 1)
@@ -461,9 +470,9 @@
461 SET(CPACK_PACKAGE_VENDOR "Stellarium's team")470 SET(CPACK_PACKAGE_VENDOR "Stellarium's team")
462 SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README")471 SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README")
463 SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING")472 SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING")
464 SET(CPACK_PACKAGE_VERSION_MAJOR ${STELLARIUM_MAJOR})473 SET(CPACK_PACKAGE_VERSION_MAJOR "${STELLARIUM_MAJOR}")
465 SET(CPACK_PACKAGE_VERSION_MINOR ${STELLARIUM_MINOR})474 SET(CPACK_PACKAGE_VERSION_MINOR "${STELLARIUM_MINOR}")
466 SET(CPACK_PACKAGE_VERSION_PATCH ${STELLARIUM_PATCH})475 SET(CPACK_PACKAGE_VERSION_PATCH "${STELLARIUM_PATCH}")
467 SET(CPACK_PACKAGE_INSTALL_DIRECTORY "stellarium")476 SET(CPACK_PACKAGE_INSTALL_DIRECTORY "stellarium")
468 SET(CPACK_SOURCE_PACKAGE_FILE_NAME "stellarium-${VERSION}")477 SET(CPACK_SOURCE_PACKAGE_FILE_NAME "stellarium-${VERSION}")
469 SET(CPACK_SOURCE_GENERATOR "TGZ")478 SET(CPACK_SOURCE_GENERATOR "TGZ")
@@ -517,8 +526,18 @@
517ENDIF()526ENDIF()
518527
519########### Generate doxygen doc ###############528########### Generate doxygen doc ###############
520CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/cmake/Doxyfile.cmake ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)529FIND_PACKAGE(Doxygen)
521ADD_CUSTOM_TARGET(apidoc doxygen ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Generate the doxygen documentation into the doc directory.")530IF(DOXYGEN_FOUND)
531 IF(DOXYGEN_DOT_FOUND)
532 SET(HAVE_DOT "YES")
533 SET(DOT_PATH ${DOXYGEN_DOT_PATH})
534 ELSE()
535 SET(HAVE_DOT "NO")
536 SET(DOT_PATH "")
537 ENDIF()
538 CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/cmake/Doxyfile.cmake ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
539 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.")
540ENDIF()
522541
523##################### Generate translation copying script ######################542##################### Generate translation copying script ######################
524IF(WIN32)543IF(WIN32)
525544
=== modified file 'cmake/Doxyfile.cmake'
--- cmake/Doxyfile.cmake 2016-04-21 07:15:21 +0000
+++ cmake/Doxyfile.cmake 2016-06-12 13:59:22 +0000
@@ -150,7 +150,7 @@
150# shortest path that makes the file name unique will be used150# shortest path that makes the file name unique will be used
151# The default value is: YES.151# The default value is: YES.
152152
153FULL_PATH_NAMES = NO153FULL_PATH_NAMES = YES
154154
155# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.155# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
156# Stripping is only done if one of the specified strings matches the left-hand156# Stripping is only done if one of the specified strings matches the left-hand
@@ -2026,6 +2026,9 @@
2026# run, you must also specify the path to the tagfile here.2026# run, you must also specify the path to the tagfile here.
20272027
2028TAGFILES = qt.tag=http://doc.qt.io/qt-5/2028TAGFILES = qt.tag=http://doc.qt.io/qt-5/
2029 qtcore.tags=http://doc.qt.io/qt-5/ \
2030 qtgui.tags=http://doc.qt.io/qt-5/ \
2031 qtwidgets.tags=http://doc.qt.io/qt-5/
20292032
2030# When a file name is specified after GENERATE_TAGFILE, doxygen will create a2033# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
2031# tag file that is based on the input files it reads. See section "Linking to2034# tag file that is based on the input files it reads. See section "Linking to
@@ -2101,7 +2104,7 @@
2101# set to NO2104# set to NO
2102# The default value is: YES.2105# The default value is: YES.
21032106
2104HAVE_DOT = NO2107HAVE_DOT = @HAVE_DOT@
21052108
2106# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed2109# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
2107# to run in parallel. When set to 0 doxygen will base this on the number of2110# to run in parallel. When set to 0 doxygen will base this on the number of
@@ -2143,7 +2146,7 @@
2143# The default value is: YES.2146# The default value is: YES.
2144# This tag requires that the tag HAVE_DOT is set to YES.2147# This tag requires that the tag HAVE_DOT is set to YES.
21452148
2146CLASS_GRAPH = NO2149CLASS_GRAPH = YES
21472150
2148# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a2151# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
2149# graph for each documented class showing the direct and indirect implementation2152# graph for each documented class showing the direct and indirect implementation
@@ -2152,7 +2155,7 @@
2152# The default value is: YES.2155# The default value is: YES.
2153# This tag requires that the tag HAVE_DOT is set to YES.2156# This tag requires that the tag HAVE_DOT is set to YES.
21542157
2155COLLABORATION_GRAPH = NO2158COLLABORATION_GRAPH = YES
21562159
2157# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for2160# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
2158# groups, showing the direct groups dependencies.2161# groups, showing the direct groups dependencies.
@@ -2275,7 +2278,7 @@
2275# found. If left blank, it is assumed the dot tool can be found in the path.2278# found. If left blank, it is assumed the dot tool can be found in the path.
2276# This tag requires that the tag HAVE_DOT is set to YES.2279# This tag requires that the tag HAVE_DOT is set to YES.
22772280
2278DOT_PATH =2281DOT_PATH = "@DOT_PATH@"
22792282
2280# The DOTFILE_DIRS tag can be used to specify one or more directories that2283# The DOTFILE_DIRS tag can be used to specify one or more directories that
2281# contain dot files that are included in the documentation (see the \dotfile2284# contain dot files that are included in the documentation (see the \dotfile
22822285
=== modified file 'data/CMakeLists.txt'
--- data/CMakeLists.txt 2016-05-29 09:27:35 +0000
+++ data/CMakeLists.txt 2016-06-12 13:59:22 +0000
@@ -53,13 +53,16 @@
53ENDIF()53ENDIF()
5454
55# install Scenery3d shaders55# install Scenery3d shaders
56IF(USE_PLUGIN_SCENERY3D)
56INSTALL(DIRECTORY shaders/ DESTINATION share/${PACKAGE}/data/shaders FILES_MATCHING 57INSTALL(DIRECTORY shaders/ DESTINATION share/${PACKAGE}/data/shaders FILES_MATCHING
57 PATTERN "s3d_*.vert" PATTERN "s3d_*.geom" PATTERN "s3d_*.frag")58 PATTERN "s3d_*.vert"
58 59 PATTERN "s3d_*.geom"
60 PATTERN "s3d_*.frag")
59# install Scenery3D docs for Windows61# install Scenery3D docs for Windows
60IF(WIN32)62IF(WIN32)
61 INSTALL(FILES ../plugins/Scenery3d/doc/Scenery3d.pdf DESTINATION share/${PACKAGE}/data)63 INSTALL(FILES ../plugins/Scenery3d/doc/Scenery3d.pdf DESTINATION share/${PACKAGE}/data)
62ENDIF(WIN32)64ENDIF(WIN32)
65ENDIF()
6366
64IF (BUILD_FOR_MAEMO)67IF (BUILD_FOR_MAEMO)
65 INSTALL(FILES maemo/stellarium.desktop DESTINATION /usr/share/applications/hildon)68 INSTALL(FILES maemo/stellarium.desktop DESTINATION /usr/share/applications/hildon)
6669
=== modified file 'data/gui/normalStyle.css'
--- data/gui/normalStyle.css 2015-08-18 06:29:08 +0000
+++ data/gui/normalStyle.css 2016-06-12 13:59:22 +0000
@@ -149,7 +149,7 @@
149 font-size: 12px;149 font-size: 12px;
150}150}
151151
152QLineEdit[enabled="false"] {152QLineEdit:disabled {
153 background: rgb(90, 90, 90);153 background: rgb(90, 90, 90);
154}154}
155155
156156
=== modified file 'doc/DoxygenLayout.xml'
--- doc/DoxygenLayout.xml 2014-06-22 14:08:40 +0000
+++ doc/DoxygenLayout.xml 2016-06-12 13:59:22 +0000
@@ -18,7 +18,7 @@
18 <tab type="user" url="@ref scripting" visible="yes" title="Scripting" intro=""/>18 <tab type="user" url="@ref scripting" visible="yes" title="Scripting" intro=""/>
19 <tab type="user" url="@ref plugins" visible="yes" title="Plugins" intro=""/>19 <tab type="user" url="@ref plugins" visible="yes" title="Plugins" intro=""/>
20 <tab type="user" url="@ref fileStructure" visible="yes" title="File Structure" intro=""/>20 <tab type="user" url="@ref fileStructure" visible="yes" title="File Structure" intro=""/>
21 <tab type="files" visible="no" title="">21 <tab type="files" visible="yes" title="">
22 <tab type="filelist" visible="yes" title="" intro=""/>22 <tab type="filelist" visible="yes" title="" intro=""/>
23 <tab type="globals" visible="yes" title="" intro=""/>23 <tab type="globals" visible="yes" title="" intro=""/>
24 </tab>24 </tab>
2525
=== modified file 'doc/doxygen.css'
--- doc/doxygen.css 2015-06-08 20:08:26 +0000
+++ doc/doxygen.css 2016-06-12 13:59:22 +0000
@@ -1193,7 +1193,8 @@
1193 float: right;1193 float: right;
1194 height: auto;1194 height: auto;
1195 margin: 0 20px 10px 10px;1195 margin: 0 20px 10px 10px;
1196 width: 200px;1196 min-width: 200px;
1197 max-width: 400px;
1197}1198}
11981199
1199div.toc li {1200div.toc li {
12001201
=== modified file 'doc/mainpage.doxygen'
--- doc/mainpage.doxygen 2016-02-25 17:31:00 +0000
+++ doc/mainpage.doxygen 2016-06-12 13:59:22 +0000
@@ -32,9 +32,9 @@
32<ul>32<ul>
33<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>33<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>
34<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>34<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>
35<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>35<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>
36<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>36<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>
37<li>the script engine (StelScriptMgr) allows scripts to calls slots from the core and StelModules slots.</li>37<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>
38</ul>38</ul>
39@image html stellarium-architecture.png39@image html stellarium-architecture.png
4040
4141
=== modified file 'doc/plugIns.doxygen'
--- doc/plugIns.doxygen 2016-04-21 06:48:03 +0000
+++ doc/plugIns.doxygen 2016-06-12 13:59:22 +0000
@@ -65,6 +65,7 @@
65 - @ref meteorShowers65 - @ref meteorShowers
66 - @ref pointerCoordinates66 - @ref pointerCoordinates
67 - @ref archaeoLines67 - @ref archaeoLines
68 - @ref remoteControl
6869
69You can find some untechnical details on our wiki [Plugins](http://www.stellarium.org/wiki/index.php/Plugins) page.70You can find some untechnical details on our wiki [Plugins](http://www.stellarium.org/wiki/index.php/Plugins) page.
7071
7172
=== added file 'guide/pictures/remote.png'
72Binary files guide/pictures/remote.png 1970-01-01 00:00:00 +0000 and guide/pictures/remote.png 2016-06-12 13:59:22 +0000 differ73Binary files guide/pictures/remote.png 1970-01-01 00:00:00 +0000 and guide/pictures/remote.png 2016-06-12 13:59:22 +0000 differ
=== added file 'guide/pictures/remote_web.png'
73Binary files guide/pictures/remote_web.png 1970-01-01 00:00:00 +0000 and guide/pictures/remote_web.png 2016-06-12 13:59:22 +0000 differ74Binary files guide/pictures/remote_web.png 1970-01-01 00:00:00 +0000 and guide/pictures/remote_web.png 2016-06-12 13:59:22 +0000 differ
=== modified file 'guide/plg_interfaces.tex'
--- guide/plg_interfaces.tex 2016-05-05 23:42:27 +0000
+++ guide/plg_interfaces.tex 2016-06-12 13:59:22 +0000
@@ -373,7 +373,101 @@
373\section{Remote Control}373\section{Remote Control}
374\label{sec:plugin:RemoteControl}374\label{sec:plugin:RemoteControl}
375375
376[This will come as user documentation from SoCiS2015 work]376The Remote Control plugin was developed in 2015 during the
377\href{http://sophia.estec.esa.int/socis/}{ESA Summer of Code in Space}
378initiative. It enables the user to control Stellarium through an external web
379interface using a standard web browser like Firefox or Chrome, instead of using
380the main GUI. This works on the same computer Stellarium runs as well as over
381the network. Even more, multiple "remote controls" can access the same
382Stellarium instance at the same time, without getting in the way of each other.
383Much of the functionality the main interface provides is already available
384through it, and it is still getting extended.
385
386The plugin may be useful for presentation scenarios, hiding the GUI from the
387audience and allowing the presenter to change settings on a separate monitor
388without showing distracting dialog windows. It also allows to start and stop
389scripts remotely. Because the web interface can be customized (or completely
390replaced) with some knowledge of HTML, CSS and JavaScript, another possibility
391is a kiosk mode, where untrusted users can execute a variety of predefined
392actions (like starting recorded tours) without having access to all Stellarium
393settings. The web API can also be accessed directly (without using a browser
394and the HTML interface), allowing control of Stellarium with external programs
395and scripts using HTTP calls like with the tools \file{wget} and \file{curl}.
396
397\subsection{Using the plugin}
398\label{sec:plugins:RemoteControl:using}
399
400\begin{figure}[h]
401\centering\includegraphics[width=\columnwidth]{remote_web}
402\caption{The default remote control web interface}
403\end{figure}
404
405After enabling the plugin, you can set it up through the configuration dialog.
406When ``Enable automatically on startup'' is checked (it is by default), the web
407server is automatically started whenever Stellarium starts. You can also
408manually start/stop the server using the ``Server enabled'' checkbox and the
409button \includegraphics[scale=0.5]{remote} in the toolbar.
410
411The plugin starts a HTTP server on the specified port. The default port is
4128090, so you can try to reach the remote control after enabling it by starting
413a browser on the same computer and entering \url{http://localhost:8090} in the
414address bar. When trying to access the remote control from another computer,
415you need the IP address or the hostname of the server on which Stellarium runs.
416The plugin shows the locally detected address, but depending on your network or
417if you need external access you might need to use a different one
418--- contact your network administrator if you need help with that.
419
420The access to the remote control may optionally be restricted with a simple
421password.
422
423\textbf{Warning:} \emph{currently no network encryption is used, meaning that
424an attacker having access to your network can easily find out the password by
425waiting for a user entering it. Access from the Internet to the
426plugin should generally be restricted, except if countermeasures such as VPN
427usage are taken! If you are in a home network using NAT (network access
428translation), this should be enough for basic security except if port
429forwarding or a DMZ is configured.}
430
431If you are familiar with the main Stellarium interface, you should easily find
432your way around the web interface. Tabs at the top allow access to
433different settings and controls. The remote control automatically uses the
434same language as set in the main program.
435
436The contents of the various tabs:
437\begin{description}
438\item[Main] Contains the time controls and most of the buttons of the
439main bottom toolbar. An additional control allows moving the view like when
440dragging the mouse or using the arrow keys in Stellarium, and a slider enables
441the changing of the field of view. There are also buttons to quickly execute
442time jumps using the commonly used astronomical time intervals.
443\item[Selection] Allows searching and selecting objects like in \autoref{sec:gui:search}.
444SIMBAD search is also supported. Quick select buttons are available for the
445primary solar system objects. It also displays the information text for current
446selection.
447\item[Sky] Settings related to the sky display as shown in the ``View'' dialog
448as shown in \autoref{sec:gui:view:sky}.
449\item[DSO] The deep-sky object catalog, filter and display settings like in
450\autoref{sec:gui:view:markings}.
451\item[Landscape] Changing and configuring the background landscape, see
452\autoref{sec:gui:view:landscape}
453\item[Actions and scripts] Lists all registered actions, and allows starting
454and stopping of scripts (\autoref{ch:scripting}). If there is no button for the
455action you want in another tab, you can find all actions which can be
456configured as a keyboard shortcut (\autoref{sec:gui:configuration}) here.
457\item[Location] Allows changing the location, like in
458\autoref{sec:gui:location}. Custom location saving is currently not
459supported.
460\item[Projection] Switch the projection method used, like \autoref{sec:gui:view:markings}.
461\end{description}
462
463\subsection{Developer information}
464\label{sec:plugins:RemoteControl:developer}
465
466If you are a developer and would like to add functionality to the Remote
467Control API, customize the web interface or access the API through another
468program, further information can be found in the
469\href{http://stellarium.org/doc-plugins/head/}{plugin's developer
470documentation}.
377471
378472
379% \newpage473% \newpage
380474
=== modified file 'plugins/ArchaeoLines/src/ArchaeoLines.cpp'
--- plugins/ArchaeoLines/src/ArchaeoLines.cpp 2015-12-29 13:15:57 +0000
+++ plugins/ArchaeoLines/src/ArchaeoLines.cpp 2016-06-12 13:59:22 +0000
@@ -89,7 +89,7 @@
89 objMgr=GETSTELMODULE(StelObjectMgr);89 objMgr=GETSTELMODULE(StelObjectMgr);
90 Q_ASSERT(objMgr);90 Q_ASSERT(objMgr);
9191
92 // optimize readabiity so that each upper line of the lunistice doubles is labeled.92 // optimize readability so that each upper line of the lunistice doubles is labeled.
93 equinoxLine = new ArchaeoLine(ArchaeoLine::Equinox, 0.0);93 equinoxLine = new ArchaeoLine(ArchaeoLine::Equinox, 0.0);
94 northernSolsticeLine = new ArchaeoLine(ArchaeoLine::Solstices, 23.50);94 northernSolsticeLine = new ArchaeoLine(ArchaeoLine::Solstices, 23.50);
95 southernSolsticeLine = new ArchaeoLine(ArchaeoLine::Solstices, -23.50);95 southernSolsticeLine = new ArchaeoLine(ArchaeoLine::Solstices, -23.50);
@@ -116,6 +116,7 @@
116116
117 configDialog = new ArchaeoLinesDialog();117 configDialog = new ArchaeoLinesDialog();
118 conf = StelApp::getInstance().getSettings();118 conf = StelApp::getInstance().getSettings();
119
119}120}
120121
121ArchaeoLines::~ArchaeoLines()122ArchaeoLines::~ArchaeoLines()
@@ -188,7 +189,8 @@
188 StelApp& app = StelApp::getInstance();189 StelApp& app = StelApp::getInstance();
189190
190 // Create action for enable/disable & hook up signals 191 // Create action for enable/disable & hook up signals
191 addAction("actionShow_Archaeo_Lines", N_("ArchaeoLines"), N_("ArchaeoLines"), "enabled", "Ctrl+U");192 QString section=N_("ArchaeoLines");
193 addAction("actionShow_Archaeo_Lines", section, N_("ArchaeoLines"), "enabled", "Ctrl+U");
192194
193 // Add a toolbar button195 // Add a toolbar button
194 try196 try
@@ -208,6 +210,16 @@
208 {210 {
209 qWarning() << "WARNING: unable to create toolbar button for ArchaeoLines plugin: " << e.what();211 qWarning() << "WARNING: unable to create toolbar button for ArchaeoLines plugin: " << e.what();
210 }212 }
213 addAction("actionAL_showEquinoxLine", section, N_("Show Line for Equinox"), "flagShowEquinox" ); // No Shortcuts configured.
214 addAction("actionAL_showSolsticeLines", section, N_("Show Line for Solstices"), "flagShowSolstices" ); // No Shortcuts configured.
215 addAction("actionAL_showCrossquarterLines", section, N_("Show Line for Crossquarter"), "flagShowCrossquarters" ); // No Shortcuts configured.
216 addAction("actionAL_showMajorStandstillLines", section, N_("Show Line for Major Standstill"), "flagShowMajorStandstills"); // No Shortcuts configured.
217 addAction("actionAL_showMinorStandstillLines", section, N_("Show Line for Minor Standstill"), "flagShowMinorStandstills"); // No Shortcuts configured.
218 addAction("actionAL_showZenithPassageLine", section, N_("Show Line for Zenith Passage"), "flagShowZenithPassage" ); // No Shortcuts configured.
219 addAction("actionAL_showNadirPassageLine", section, N_("Show Line for Nadir Passage"), "flagShowNadirPassage" ); // No Shortcuts configured.
220 addAction("actionAL_showSelectedObjectLine", section, N_("Show Line for Selected Object"), "flagShowSelectedObject" ); // No Shortcuts configured.
221 addAction("actionAL_showCurrentSunLine", section, N_("Show Line for Current Sun"), "flagShowCurrentSun" ); // No Shortcuts configured.
222 addAction("actionAL_showCurrentMoonLine", section, N_("Show Line for Current Moon"), "flagShowCurrentMoon" ); // No Shortcuts configured.
211}223}
212224
213void ArchaeoLines::update(double deltaTime)225void ArchaeoLines::update(double deltaTime)
@@ -450,7 +462,7 @@
450 // indicators for current declinations (those move fast over days...)462 // indicators for current declinations (those move fast over days...)
451 showCurrentSun(conf->value("ArchaeoLines/show_current_sun", true).toBool());463 showCurrentSun(conf->value("ArchaeoLines/show_current_sun", true).toBool());
452 showCurrentMoon(conf->value("ArchaeoLines/show_current_moon", true).toBool());464 showCurrentMoon(conf->value("ArchaeoLines/show_current_moon", true).toBool());
453 showCurrentPlanet(conf->value("ArchaeoLines/show_current_planet", "none").toString());465 showCurrentPlanetNamed(conf->value("ArchaeoLines/show_current_planet", "none").toString());
454466
455 enableArchaeoLines(conf->value("ArchaeoLines/enable_at_startup", false).toBool());467 enableArchaeoLines(conf->value("ArchaeoLines/enable_at_startup", false).toBool());
456}468}
@@ -526,15 +538,20 @@
526538
527void ArchaeoLines::showCurrentPlanet(ArchaeoLine::Line l)539void ArchaeoLines::showCurrentPlanet(ArchaeoLine::Line l)
528{540{
529 enumShowCurrentPlanet=l;541 if(l!=enumShowCurrentPlanet)
530 const char *planetStrings[]={"none", "Mercury", "Venus", "Mars", "Jupiter", "Saturn"};542 {
531543 enumShowCurrentPlanet=l;
532 conf->setValue("ArchaeoLines/show_current_planet", planetStrings[l-ArchaeoLine::CurrentPlanetNone]);544 const char *planetStrings[]={"none", "Mercury", "Venus", "Mars", "Jupiter", "Saturn"};
533 currentPlanetLine->setLineType(enumShowCurrentPlanet);545
534 currentPlanetLine->setDisplayed(enumShowCurrentPlanet != ArchaeoLine::CurrentPlanetNone);546 conf->setValue("ArchaeoLines/show_current_planet", planetStrings[l-ArchaeoLine::CurrentPlanetNone]);
547 currentPlanetLine->setLineType(enumShowCurrentPlanet);
548 currentPlanetLine->setDisplayed(enumShowCurrentPlanet != ArchaeoLine::CurrentPlanetNone);
549
550 emit currentPlanetChanged(l);
551 }
535}552}
536553
537void ArchaeoLines::showCurrentPlanet(QString planet)554void ArchaeoLines::showCurrentPlanetNamed(QString planet)
538{555{
539 if (planet=="none")556 if (planet=="none")
540 enumShowCurrentPlanet=ArchaeoLine::CurrentPlanetNone;557 enumShowCurrentPlanet=ArchaeoLine::CurrentPlanetNone;
541558
=== modified file 'plugins/ArchaeoLines/src/ArchaeoLines.hpp'
--- plugins/ArchaeoLines/src/ArchaeoLines.hpp 2015-08-03 13:17:06 +0000
+++ plugins/ArchaeoLines/src/ArchaeoLines.hpp 2016-06-12 13:59:22 +0000
@@ -77,6 +77,10 @@
77 Q_OBJECT77 Q_OBJECT
78 Q_PROPERTY(Vec3f color READ getColor WRITE setColor)78 Q_PROPERTY(Vec3f color READ getColor WRITE setColor)
79 Q_PROPERTY(bool flagLabel READ isLabelVisible WRITE setLabelVisible)79 Q_PROPERTY(bool flagLabel READ isLabelVisible WRITE setLabelVisible)
80
81 //Need to register Enum with Qt to be able to use it as Q_PROPERTY
82 //or in signals/slots
83 Q_ENUMS(Line)
80public:84public:
81 enum Line {85 enum Line {
82 Equinox,86 Equinox,
@@ -174,7 +178,8 @@
174 WRITE showCurrentMoon)178 WRITE showCurrentMoon)
175 Q_PROPERTY(ArchaeoLine::Line enumShowCurrentPlanet179 Q_PROPERTY(ArchaeoLine::Line enumShowCurrentPlanet
176 READ whichCurrentPlanetDisplayed180 READ whichCurrentPlanetDisplayed
177 WRITE showCurrentPlanet)181 WRITE showCurrentPlanet
182 NOTIFY currentPlanetChanged)
178183
179public:184public:
180 ArchaeoLines();185 ArchaeoLines();
@@ -190,19 +195,7 @@
190 virtual double getCallOrder(StelModuleActionName actionName) const;195 virtual double getCallOrder(StelModuleActionName actionName) const;
191 virtual void handleKeys(class QKeyEvent* event){event->setAccepted(false);}196 virtual void handleKeys(class QKeyEvent* event){event->setAccepted(false);}
192 virtual bool configureGui(bool show=true);197 virtual bool configureGui(bool show=true);
193 bool isEnabled() const {return flagShowArchaeoLines;}
194 bool isDmsFormat() const { return flagUseDmsFormat; } // NOT SURE IF USEFUL198 bool isDmsFormat() const { return flagUseDmsFormat; } // NOT SURE IF USEFUL
195 bool isEquinoxDisplayed() const {return flagShowEquinox;}
196 bool isSolsticesDisplayed() const {return flagShowSolstices;}
197 bool isCrossquartersDisplayed() const {return flagShowCrossquarters;}
198 bool isMajorStandstillsDisplayed() const {return flagShowMajorStandstills;}
199 bool isMinorStandstillsDisplayed() const {return flagShowMinorStandstills;}
200 bool isZenithPassageDisplayed() const {return flagShowZenithPassage;}
201 bool isNadirPassageDisplayed() const {return flagShowNadirPassage;}
202 bool isSelectedObjectDisplayed() const {return flagShowSelectedObject;}
203 bool isCurrentSunDisplayed() const {return flagShowCurrentSun;}
204 bool isCurrentMoonDisplayed() const {return flagShowCurrentMoon;}
205 ArchaeoLine::Line whichCurrentPlanetDisplayed() const {return enumShowCurrentPlanet;}
206199
207 //! Restore the plug-in's settings to the default state.200 //! Restore the plug-in's settings to the default state.
208 //! Replace the plug-in's settings in Stellarium's configuration file201 //! Replace the plug-in's settings in Stellarium's configuration file
@@ -217,11 +210,27 @@
217 //! @see restoreDefaultSettings()210 //! @see restoreDefaultSettings()
218 void loadSettings();211 void loadSettings();
219212
213signals:
214 void currentPlanetChanged(ArchaeoLine::Line l); // meaningful only CurrentPlanetNone...CurrentPlanetSaturn.
220215
221public slots:216public slots:
222 void enableArchaeoLines(bool b);217 void enableArchaeoLines(bool b);
223 //void useDmsFormat(bool b);218 //void useDmsFormat(bool b);
224219
220 bool isEnabled() const {return flagShowArchaeoLines;}
221 bool isEquinoxDisplayed() const {return flagShowEquinox;}
222 bool isSolsticesDisplayed() const {return flagShowSolstices;}
223 bool isCrossquartersDisplayed() const {return flagShowCrossquarters;}
224 bool isMajorStandstillsDisplayed() const {return flagShowMajorStandstills;}
225 bool isMinorStandstillsDisplayed() const {return flagShowMinorStandstills;}
226 bool isZenithPassageDisplayed() const {return flagShowZenithPassage;}
227 bool isNadirPassageDisplayed() const {return flagShowNadirPassage;}
228 bool isSelectedObjectDisplayed() const {return flagShowSelectedObject;}
229 bool isCurrentSunDisplayed() const {return flagShowCurrentSun;}
230 bool isCurrentMoonDisplayed() const {return flagShowCurrentMoon;}
231 ArchaeoLine::Line whichCurrentPlanetDisplayed() const {return enumShowCurrentPlanet;}
232
233
225 void showEquinox(bool b);234 void showEquinox(bool b);
226 void showSolstices(bool b);235 void showSolstices(bool b);
227 void showCrossquarters(bool b);236 void showCrossquarters(bool b);
@@ -233,7 +242,7 @@
233 void showCurrentSun(bool b);242 void showCurrentSun(bool b);
234 void showCurrentMoon(bool b);243 void showCurrentMoon(bool b);
235 void showCurrentPlanet(ArchaeoLine::Line l); // Allowed values for l: CurrentPlanetNone...CurrentPlanetSaturn.244 void showCurrentPlanet(ArchaeoLine::Line l); // Allowed values for l: CurrentPlanetNone...CurrentPlanetSaturn.
236 void showCurrentPlanet(QString planet); // Allowed values for planet: "none", "Mercury", "Venus", "Mars", "Jupiter", "Saturn".245 void showCurrentPlanetNamed(QString planet); // Allowed values for planet: "none", "Mercury", "Venus", "Mars", "Jupiter", "Saturn".
237246
238 // called by the dialog GUI, converts GUI's QColor (0..255) to Stellarium's Vec3f float color.247 // called by the dialog GUI, converts GUI's QColor (0..255) to Stellarium's Vec3f float color.
239 void setLineColor(ArchaeoLine::Line whichLine, QColor color);248 void setLineColor(ArchaeoLine::Line whichLine, QColor color);
240249
=== modified file 'plugins/ArchaeoLines/src/gui/ArchaeoLinesDialog.cpp'
--- plugins/ArchaeoLines/src/gui/ArchaeoLinesDialog.cpp 2016-01-22 11:05:08 +0000
+++ plugins/ArchaeoLines/src/gui/ArchaeoLinesDialog.cpp 2016-06-12 13:59:22 +0000
@@ -90,7 +90,8 @@
90 ui->currentMoonCheckBox->setChecked(al->isCurrentMoonDisplayed());90 ui->currentMoonCheckBox->setChecked(al->isCurrentMoonDisplayed());
91 connect(ui->currentMoonCheckBox, SIGNAL(toggled(bool)), al, SLOT(showCurrentMoon(bool)));91 connect(ui->currentMoonCheckBox, SIGNAL(toggled(bool)), al, SLOT(showCurrentMoon(bool)));
92 // Planet ComboBox requires special handling!92 // Planet ComboBox requires special handling!
93 ui->currentPlanetComboBox->setCurrentIndex(al->whichCurrentPlanetDisplayed()-ArchaeoLine::CurrentPlanetNone);93 setCurrentPlanetFromApp();
94 connect(al, SIGNAL(currentPlanetChanged(ArchaeoLine::Line)), this, SLOT(setCurrentPlanetFromApp()));
94 connect(ui->currentPlanetComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setCurrentPlanetFromGUI(int)));95 connect(ui->currentPlanetComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setCurrentPlanetFromGUI(int)));
9596
96 equinoxColor = al->getLineColor(ArchaeoLine::Equinox);97 equinoxColor = al->getLineColor(ArchaeoLine::Equinox);
@@ -177,6 +178,12 @@
177 al->showCurrentPlanet((ArchaeoLine::Line) (ArchaeoLine::CurrentPlanetNone+index));178 al->showCurrentPlanet((ArchaeoLine::Line) (ArchaeoLine::CurrentPlanetNone+index));
178}179}
179180
181void ArchaeoLinesDialog::setCurrentPlanetFromApp()
182{
183 Q_ASSERT(al);
184 ui->currentPlanetComboBox->setCurrentIndex(al->whichCurrentPlanetDisplayed()-ArchaeoLine::CurrentPlanetNone);
185}
186
180187
181void ArchaeoLinesDialog::setAboutHtml(void)188void ArchaeoLinesDialog::setAboutHtml(void)
182{189{
183190
=== modified file 'plugins/ArchaeoLines/src/gui/ArchaeoLinesDialog.hpp'
--- plugins/ArchaeoLines/src/gui/ArchaeoLinesDialog.hpp 2015-05-30 19:56:47 +0000
+++ plugins/ArchaeoLines/src/gui/ArchaeoLinesDialog.hpp 2016-06-12 13:59:22 +0000
@@ -103,6 +103,7 @@
103 void resetArchaeoLinesSettings();103 void resetArchaeoLinesSettings();
104 //! setting planet requires a small function to link Combobox indices to line IDs.104 //! setting planet requires a small function to link Combobox indices to line IDs.
105 void setCurrentPlanetFromGUI(int index);105 void setCurrentPlanetFromGUI(int index);
106 void setCurrentPlanetFromApp();
106107
107};108};
108109
109110
=== modified file 'plugins/Oculars/src/Oculars.cpp'
--- plugins/Oculars/src/Oculars.cpp 2016-06-11 17:54:59 +0000
+++ plugins/Oculars/src/Oculars.cpp 2016-06-12 13:59:22 +0000
@@ -126,7 +126,7 @@
126 flagMoonScale(false),126 flagMoonScale(false),
127 maxEyepieceAngle(0.0),127 maxEyepieceAngle(0.0),
128 requireSelection(true),128 requireSelection(true),
129 flagLimitMagnitude(false), 129 flagLimitMagnitude(false),
130 useMaxEyepieceAngle(true),130 useMaxEyepieceAngle(true),
131 guiPanelEnabled(false),131 guiPanelEnabled(false),
132 flagDecimalDegrees(false),132 flagDecimalDegrees(false),
@@ -258,7 +258,7 @@
258 lens->writeToSettings(settings, index);258 lens->writeToSettings(settings, index);
259 index++;259 index++;
260 }260 }
261 261
262 settings->setValue("ocular_count", oculars.count());262 settings->setValue("ocular_count", oculars.count());
263 settings->setValue("telescope_count", telescopes.count());263 settings->setValue("telescope_count", telescopes.count());
264 settings->setValue("ccd_count", ccds.count());264 settings->setValue("ccd_count", ccds.count());
@@ -283,22 +283,22 @@
283 if (selectedCCDIndex > ccds.count())283 if (selectedCCDIndex > ccds.count())
284 {284 {
285 qWarning() << "Oculars: the selected sensor index of "285 qWarning() << "Oculars: the selected sensor index of "
286 << selectedCCDIndex << " is greater than the sensor count of "286 << selectedCCDIndex << " is greater than the sensor count of "
287 << ccds.count() << ". Module disabled!";287 << ccds.count() << ". Module disabled!";
288 ready = false;288 ready = false;
289 }289 }
290 if (selectedOcularIndex > oculars.count())290 if (selectedOcularIndex > oculars.count())
291 {291 {
292 qWarning() << "Oculars: the selected ocular index of "292 qWarning() << "Oculars: the selected ocular index of "
293 << selectedOcularIndex << " is greater than the ocular count of "293 << selectedOcularIndex << " is greater than the ocular count of "
294 << oculars.count() << ". Module disabled!";294 << oculars.count() << ". Module disabled!";
295 ready = false;295 ready = false;
296 }296 }
297 else if (selectedTelescopeIndex > telescopes.count())297 else if (selectedTelescopeIndex > telescopes.count())
298 {298 {
299 qWarning() << "Oculars: the selected telescope index of "299 qWarning() << "Oculars: the selected telescope index of "
300 << selectedTelescopeIndex << " is greater than the telescope count of "300 << selectedTelescopeIndex << " is greater than the telescope count of "
301 << telescopes.count() << ". Module disabled!";301 << telescopes.count() << ". Module disabled!";
302 ready = false;302 ready = false;
303 }303 }
304 304
@@ -785,7 +785,7 @@
785 }785 }
786 }786 }
787 guiPanelEnabled = enable;787 guiPanelEnabled = enable;
788 settings->setValue("enable_control_panel", enable); 788 settings->setValue("enable_control_panel", enable);
789 settings->sync();789 settings->sync();
790}790}
791791
@@ -833,7 +833,7 @@
833 if (oculars.isEmpty())833 if (oculars.isEmpty())
834 {834 {
835 selectedOcularIndex = -1;835 selectedOcularIndex = -1;
836 actionShowOcular->setChecked(false);836 enableOcular(false);
837 }837 }
838 else838 else
839 {839 {
@@ -847,8 +847,8 @@
847 if (telescopes.isEmpty())847 if (telescopes.isEmpty())
848 {848 {
849 selectedTelescopeIndex = -1;849 selectedTelescopeIndex = -1;
850 actionShowOcular->setChecked(false);850 enableOcular(false);
851 actionShowSensor->setChecked(false);851 toggleCCD(false);
852 }852 }
853 else853 else
854 {854 {
@@ -862,7 +862,7 @@
862 if (ccds.isEmpty())862 if (ccds.isEmpty())
863 {863 {
864 selectedCCDIndex = -1;864 selectedCCDIndex = -1;
865 actionShowSensor->setChecked(false);865 toggleCCD(false);
866 }866 }
867 else867 else
868 {868 {
@@ -895,8 +895,7 @@
895 // Close the sensor view if it's displayed895 // Close the sensor view if it's displayed
896 if (flagShowCCD)896 if (flagShowCCD)
897 {897 {
898 if (actionShowSensor->isChecked())898 toggleCCD(false);
899 actionShowSensor->setChecked(false);
900 flagShowCCD = false;899 flagShowCCD = false;
901 selectedCCDIndex = -1;900 selectedCCDIndex = -1;
902 }901 }
@@ -904,8 +903,7 @@
904 // Close the Telrad sight if it's displayed903 // Close the Telrad sight if it's displayed
905 if (flagShowTelrad)904 if (flagShowTelrad)
906 {905 {
907 if (actionShowTelrad->isChecked())906 toggleTelrad(false);
908 actionShowTelrad->setChecked(false);
909 }907 }
910908
911 // Check to ensure that we have enough oculars & telescopes, as they may have been edited in the config dialog909 // Check to ensure that we have enough oculars & telescopes, as they may have been edited in the config dialog
@@ -954,10 +952,6 @@
954 usageMessageLabelID = labelManager->labelScreen(labelText, xPosition, yPosition,952 usageMessageLabelID = labelManager->labelScreen(labelText, xPosition, yPosition,
955 true, font.pixelSize(), tcolor);953 true, font.pixelSize(), tcolor);
956 }954 }
957 // we didn't accept the new status - make sure the toolbar button reflects this
958 disconnect(actionShowOcular, SIGNAL(toggled(bool)), this, SLOT(enableOcular(bool)));
959 actionShowOcular->setChecked(false);
960 connect(actionShowOcular, SIGNAL(toggled(bool)), this, SLOT(enableOcular(bool)));
961 }955 }
962 else956 else
963 {957 {
@@ -972,6 +966,8 @@
972 guiPanel->showOcularGui();966 guiPanel->showOcularGui();
973 }967 }
974 }968 }
969
970 emit enableOcularChanged(flagShowOculars);
975}971}
976972
977void Oculars::decrementCCDIndex()973void Oculars::decrementCCDIndex()
@@ -1363,14 +1359,10 @@
1363 flagShowCCD = false;1359 flagShowCCD = false;
1364 selectedCCDIndex = -1;1360 selectedCCDIndex = -1;
1365 show = false;1361 show = false;
1366 if (actionShowSensor->isChecked())
1367 {
1368 actionShowSensor->setChecked(false);
1369 }
1370 }1362 }
13711363
1372 StelCore *core = StelApp::getInstance().getCore();1364 StelCore *core = StelApp::getInstance().getCore();
1373 StelMovementMgr *movementManager = core->getMovementMgr(); 1365 StelMovementMgr *movementManager = core->getMovementMgr();
1374 StelSkyDrawer *skyManager = core->getSkyDrawer();1366 StelSkyDrawer *skyManager = core->getSkyDrawer();
1375 skyManager->setAbsoluteStarScale(absoluteStarScale);1367 skyManager->setAbsoluteStarScale(absoluteStarScale);
1376 if (show)1368 if (show)
@@ -1378,18 +1370,10 @@
1378 initialFOV = movementManager->getCurrentFov();1370 initialFOV = movementManager->getCurrentFov();
1379 //Mutually exclusive with the ocular mode1371 //Mutually exclusive with the ocular mode
1380 hideUsageMessageIfDisplayed();1372 hideUsageMessageIfDisplayed();
1381 if (flagShowOculars)1373 enableOcular(false);
1382 {
1383 if (actionShowOcular->isChecked())
1384 {
1385 actionShowOcular->setChecked(false);
1386 }
1387 }
13881374
1389 if (flagShowTelrad) {1375 if (flagShowTelrad) {
1390 if (actionShowTelrad->isChecked()) {1376 toggleTelrad(false);
1391 actionShowTelrad->setChecked(false);
1392 }
1393 }1377 }
13941378
1395 if (selectedTelescopeIndex < 0)1379 if (selectedTelescopeIndex < 0)
@@ -1402,6 +1386,7 @@
1402 }1386 }
1403 flagShowCCD = true;1387 flagShowCCD = true;
1404 setScreenFOVForCCD();1388 setScreenFOVForCCD();
1389
1405 // Change relative scale for stars1390 // Change relative scale for stars
1406 // TODO: Finding experimental value for better rendering1391 // TODO: Finding experimental value for better rendering
1407 skyManager->setRelativeStarScale(0.6);1392 skyManager->setRelativeStarScale(0.6);
@@ -1417,7 +1402,7 @@
14171402
1418 skyManager->setRelativeStarScale(relativeStarScale);1403 skyManager->setRelativeStarScale(relativeStarScale);
1419 movementManager->setFlagTracking(false);1404 movementManager->setFlagTracking(false);
1420 //Zoom out 1405 //Zoom out
1421 if (getFlagInitFovUsage())1406 if (getFlagInitFovUsage())
1422 movementManager->zoomTo(movementManager->getInitFov());1407 movementManager->zoomTo(movementManager->getInitFov());
1423 else1408 else
@@ -1434,51 +1419,42 @@
1434 guiPanel->foldGui();1419 guiPanel->foldGui();
1435 }1420 }
1436 }1421 }
1422
1423 emit enableCCDChanged(flagShowCCD);
1437}1424}
14381425
1439void Oculars::toggleCCD()1426void Oculars::toggleCCD()
1440{1427{
1441 if (flagShowCCD)1428 toggleCCD(!flagShowCCD);
1442 {
1443 toggleCCD(false);
1444 }
1445 else
1446 {
1447 toggleCCD(true);
1448 }
1449}1429}
14501430
1451void Oculars::toggleCrosshairs(bool show)1431void Oculars::toggleCrosshairs(bool show)
1452{1432{
1453 if (show && flagShowOculars)1433 if(show != flagShowCrosshairs)
1454 {1434 {
1455 flagShowCrosshairs = true;1435 flagShowCrosshairs = show;
1456 }1436 emit enableCrosshairsChanged(show);
1457 else
1458 {
1459 flagShowCrosshairs = false;
1460 }1437 }
1461}1438}
14621439
1463void Oculars::toggleTelrad(bool show)1440void Oculars::toggleTelrad(bool show)
1464{1441{
1465 if (show)1442 if(show!=flagShowTelrad)
1466 {1443 {
1467 hideUsageMessageIfDisplayed();1444 if (show)
1468 if (actionShowOcular->isChecked())1445 {
1469 actionShowOcular->setChecked(false);1446 hideUsageMessageIfDisplayed();
1470 if (actionShowSensor->isChecked())1447 enableOcular(false);
1471 actionShowSensor->setChecked(false);1448 toggleCCD(false);
1449 }
1450 flagShowTelrad = show;
1451 emit enableTelradChanged(flagShowTelrad);
1472 }1452 }
1473 flagShowTelrad = show;
1474}1453}
14751454
1476void Oculars::toggleTelrad()1455void Oculars::toggleTelrad()
1477{1456{
1478 if (flagShowTelrad)1457 toggleTelrad(!flagShowTelrad);
1479 toggleTelrad(false);
1480 else
1481 toggleTelrad(true);
1482}1458}
14831459
1484/* ****************************************************************************************************************** */1460/* ****************************************************************************************************************** */
@@ -1493,8 +1469,7 @@
1493 Q_ASSERT(gui);1469 Q_ASSERT(gui);
14941470
1495 QString ocularsGroup = N_("Oculars");1471 QString ocularsGroup = N_("Oculars");
1496 actionShowOcular = addAction("actionShow_Ocular", ocularsGroup, N_("Ocular view"), "enableOcular(bool)", "Ctrl+O");1472 actionShowOcular = addAction("actionShow_Ocular", ocularsGroup, N_("Ocular view"), "enableOcular", "Ctrl+O");
1497 actionShowOcular->setChecked(flagShowOculars);
1498 // Make a toolbar button1473 // Make a toolbar button
1499 try1474 try
1500 {1475 {
@@ -1510,9 +1485,9 @@
1510 }1485 }
15111486
1512 actionMenu = addAction("actionShow_Ocular_Menu", ocularsGroup, N_("Oculars popup menu"), "displayPopupMenu()", "Alt+O");1487 actionMenu = addAction("actionShow_Ocular_Menu", ocularsGroup, N_("Oculars popup menu"), "displayPopupMenu()", "Alt+O");
1513 actionShowCrosshairs = addAction("actionShow_Ocular_Crosshairs", ocularsGroup, N_("Show crosshairs"), "toggleCrosshairs(bool)", "Alt+C");1488 actionShowCrosshairs = addAction("actionShow_Ocular_Crosshairs", ocularsGroup, N_("Show crosshairs"), "enableCrosshairs", "Alt+C");
1514 actionShowSensor = addAction("actionShow_Sensor", ocularsGroup, N_("Image sensor frame"), "toggleCCD(bool)");1489 actionShowSensor = addAction("actionShow_Sensor", ocularsGroup, N_("Image sensor frame"), "enableCCD");
1515 actionShowTelrad = addAction("actionShow_Telrad", ocularsGroup, N_("Telrad sight"), "toggleTelrad(bool)", "Ctrl+B");1490 actionShowTelrad = addAction("actionShow_Telrad", ocularsGroup, N_("Telrad sight"), "enableTelrad", "Ctrl+B");
1516 actionConfiguration = addAction("actionOpen_Oculars_Configuration", ocularsGroup, N_("Oculars plugin configuration"), ocularDialog, "visible");1491 actionConfiguration = addAction("actionOpen_Oculars_Configuration", ocularsGroup, N_("Oculars plugin configuration"), ocularDialog, "visible");
1517 // Select next telescope via keyboard1492 // Select next telescope via keyboard
1518 addAction("actionShow_Telescope_Increment", ocularsGroup, N_("Select next telescope"), "incrementTelescopeIndex()", "");1493 addAction("actionShow_Telescope_Increment", ocularsGroup, N_("Select next telescope"), "incrementTelescopeIndex()", "");
@@ -1556,11 +1531,11 @@
15561531
1557void Oculars::paintCCDBounds()1532void Oculars::paintCCDBounds()
1558{1533{
1559 StelCore *core = StelApp::getInstance().getCore(); 1534 StelCore *core = StelApp::getInstance().getCore();
1560 StelProjector::StelProjectorParams params = core->getCurrentStelProjectorParams();1535 StelProjector::StelProjectorParams params = core->getCurrentStelProjectorParams();
1561 Lens *lens = selectedLensIndex >=0 ? lense[selectedLensIndex] : NULL;1536 Lens *lens = selectedLensIndex >=0 ? lense[selectedLensIndex] : NULL;
15621537
1563 const StelProjectorP projector = core->getProjection(StelCore::FrameEquinoxEqu); 1538 const StelProjectorP projector = core->getProjection(StelCore::FrameEquinoxEqu);
1564 double screenFOV = params.fov;1539 double screenFOV = params.fov;
15651540
1566 // draw sensor rectangle1541 // draw sensor rectangle
@@ -1648,9 +1623,9 @@
16481623
1649 //painter.setColor(0.60f, 0.20f, 0.20f, .5f);1624 //painter.setColor(0.60f, 0.20f, 0.20f, .5f);
1650 painter.drawCircle(params.viewportCenter[0] * params.devicePixelsPerPixel,1625 painter.drawCircle(params.viewportCenter[0] * params.devicePixelsPerPixel,
1651 params.viewportCenter[1] * params.devicePixelsPerPixel, in_oag_r);1626 params.viewportCenter[1] * params.devicePixelsPerPixel, in_oag_r);
1652 painter.drawCircle(params.viewportCenter[0] * params.devicePixelsPerPixel,1627 painter.drawCircle(params.viewportCenter[0] * params.devicePixelsPerPixel,
1653 params.viewportCenter[1] * params.devicePixelsPerPixel, out_oag_r);1628 params.viewportCenter[1] * params.devicePixelsPerPixel, out_oag_r);
16541629
1655 QTransform oag_transform = QTransform().translate(params.viewportCenter[0] * params.devicePixelsPerPixel,1630 QTransform oag_transform = QTransform().translate(params.viewportCenter[0] * params.devicePixelsPerPixel,
1656 params.viewportCenter[1] * params.devicePixelsPerPixel).rotate(-(ccd->chipRotAngle() + polarAngle + ccd->prismPosAngle()));1631 params.viewportCenter[1] * params.devicePixelsPerPixel).rotate(-(ccd->chipRotAngle() + polarAngle + ccd->prismPosAngle()));
@@ -1786,8 +1761,8 @@
1786 reticleTexture->getDimensions(textureWidth, textureHeight);1761 reticleTexture->getDimensions(textureWidth, textureHeight);
17871762
1788 painter.drawSprite2dMode(params.viewportXywh[2] / 2 * params.devicePixelsPerPixel,1763 painter.drawSprite2dMode(params.viewportXywh[2] / 2 * params.devicePixelsPerPixel,
1789 params.viewportXywh[3] / 2 * params.devicePixelsPerPixel,1764 params.viewportXywh[3] / 2 * params.devicePixelsPerPixel,
1790 inner, reticleRotation);1765 inner, reticleRotation);
1791 }1766 }
17921767
1793 if (oculars[selectedOcularIndex]->hasPermanentCrosshair())1768 if (oculars[selectedOcularIndex]->hasPermanentCrosshair())
@@ -1845,7 +1820,7 @@
1845void Oculars::paintText(const StelCore* core)1820void Oculars::paintText(const StelCore* core)
1846{1821{
1847 const StelProjectorP prj = core->getProjection(StelCore::FrameAltAz);1822 const StelProjectorP prj = core->getProjection(StelCore::FrameAltAz);
1848 StelPainter painter(prj); 1823 StelPainter painter(prj);
18491824
1850 // Get the current instruments1825 // Get the current instruments
1851 CCD *ccd = NULL;1826 CCD *ccd = NULL;
@@ -1922,7 +1897,7 @@
1922 QString ocularFOVLabel = QString(q_("Ocular aFOV: %1")).arg(ocularFov);1897 QString ocularFOVLabel = QString(q_("Ocular aFOV: %1")).arg(ocularFov);
1923 painter.drawText(xPosition, yPosition, ocularFOVLabel);1898 painter.drawText(xPosition, yPosition, ocularFOVLabel);
1924 yPosition-=lineHeight;1899 yPosition-=lineHeight;
1925 1900
1926 QString lensNumberLabel;1901 QString lensNumberLabel;
1927 // Barlow and Shapley lens1902 // Barlow and Shapley lens
1928 if (lens != NULL) // it's null if lens is not selected (lens index = -1)1903 if (lens != NULL) // it's null if lens is not selected (lens index = -1)
@@ -1943,7 +1918,7 @@
1943 }1918 }
1944 painter.drawText(xPosition, yPosition, lensNumberLabel);1919 painter.drawText(xPosition, yPosition, lensNumberLabel);
1945 yPosition-=lineHeight;1920 yPosition-=lineHeight;
1946 1921
1947 // The telescope1922 // The telescope
1948 QString telescopeString = "";1923 QString telescopeString = "";
1949 QString magString = "";1924 QString magString = "";
@@ -2014,7 +1989,7 @@
2014 .arg(name);1989 .arg(name);
2015 }1990 }
2016 // The telescope1991 // The telescope
2017 QString telescopeNumberLabel; 1992 QString telescopeNumberLabel;
2018 if (telescopeName.isEmpty())1993 if (telescopeName.isEmpty())
2019 {1994 {
2020 telescopeNumberLabel = QString(q_("Telescope #%1"))1995 telescopeNumberLabel = QString(q_("Telescope #%1"))
@@ -2051,7 +2026,7 @@
2051 if (!src.copy(ocularIniPath))2026 if (!src.copy(ocularIniPath))
2052 {2027 {
2053 qWarning() << "Oculars::validateIniFile cannot copy default_ocular.ini resource to [non-existing] "2028 qWarning() << "Oculars::validateIniFile cannot copy default_ocular.ini resource to [non-existing] "
2054 + ocularIniPath;2029 + ocularIniPath;
2055 }2030 }
2056 else2031 else
2057 {2032 {
@@ -2256,7 +2231,7 @@
2256 }2231 }
2257 telescope = telescopes[selectedTelescopeIndex];2232 telescope = telescopes[selectedTelescopeIndex];
2258 core->setFlipHorz(telescope->isHFlipped());2233 core->setFlipHorz(telescope->isHFlipped());
2259 core->setFlipVert(telescope->isVFlipped()); 2234 core->setFlipVert(telescope->isVFlipped());
2260 }2235 }
22612236
2262 // Change relative and absolute scales for stars2237 // Change relative and absolute scales for stars
@@ -2308,7 +2283,7 @@
2308QMenu* Oculars::addLensSubmenu(QMenu* parent)2283QMenu* Oculars::addLensSubmenu(QMenu* parent)
2309{2284{
2310 Q_ASSERT(parent);2285 Q_ASSERT(parent);
2311 2286
2312 QMenu *submenu = new QMenu(q_("&Lens"), parent);2287 QMenu *submenu = new QMenu(q_("&Lens"), parent);
2313 submenu->addAction(q_("&Previous lens"), this, SLOT(decrementLensIndex()));2288 submenu->addAction(q_("&Previous lens"), this, SLOT(decrementLensIndex()));
2314 submenu->addAction(q_("&Next lens"), this, SLOT(incrementLensIndex()));2289 submenu->addAction(q_("&Next lens"), this, SLOT(incrementLensIndex()));
@@ -2371,7 +2346,7 @@
2371void Oculars::setFlagDecimalDegrees(const bool b)2346void Oculars::setFlagDecimalDegrees(const bool b)
2372{2347{
2373 flagDecimalDegrees = b;2348 flagDecimalDegrees = b;
2374 settings->setValue("use_decimal_degrees", b); 2349 settings->setValue("use_decimal_degrees", b);
2375 settings->sync();2350 settings->sync();
2376}2351}
23772352
23782353
=== modified file 'plugins/Oculars/src/Oculars.hpp'
--- plugins/Oculars/src/Oculars.hpp 2016-06-11 17:54:59 +0000
+++ plugins/Oculars/src/Oculars.hpp 2016-06-12 13:59:22 +0000
@@ -75,6 +75,12 @@
75class Oculars : public StelModule75class Oculars : public StelModule
76{76{
77 Q_OBJECT77 Q_OBJECT
78
79 Q_PROPERTY(bool enableOcular READ getEnableOcular WRITE enableOcular NOTIFY enableOcularChanged)
80 Q_PROPERTY(bool enableCrosshairs READ getEnableCrosshairs WRITE toggleCrosshairs NOTIFY enableCrosshairsChanged)
81 Q_PROPERTY(bool enableCCD READ getEnableCCD WRITE toggleCCD NOTIFY enableCCDChanged)
82 Q_PROPERTY(bool enableTelrad READ getEnableTelrad WRITE toggleTelrad NOTIFY enableTelradChanged)
83
78 //BM: Temporary, until the GUI is finalized and some other method of getting84 //BM: Temporary, until the GUI is finalized and some other method of getting
79 //info from the main class is implemented.85 //info from the main class is implemented.
80 friend class OcularsGuiPanel;86 friend class OcularsGuiPanel;
@@ -119,6 +125,7 @@
119 //! This method is called with we detect that our hot key is pressed. It handles125 //! This method is called with we detect that our hot key is pressed. It handles
120 //! determining if we should do anything - based on a selected object.126 //! determining if we should do anything - based on a selected object.
121 void enableOcular(bool b);127 void enableOcular(bool b);
128 bool getEnableOcular() const { return flagShowOculars; }
122 void incrementCCDIndex();129 void incrementCCDIndex();
123 void incrementOcularIndex();130 void incrementOcularIndex();
124 void incrementTelescopeIndex();131 void incrementTelescopeIndex();
@@ -133,9 +140,12 @@
133 void toggleCCD(bool show);140 void toggleCCD(bool show);
134 //! Toggles the sensor frame overlay (overloaded for blind switching).141 //! Toggles the sensor frame overlay (overloaded for blind switching).
135 void toggleCCD();142 void toggleCCD();
143 bool getEnableCCD() const { return flagShowCCD; }
136 void toggleCrosshairs(bool show = true);144 void toggleCrosshairs(bool show = true);
145 bool getEnableCrosshairs() const { return flagShowCrosshairs; }
137 //! Toggles the Telrad sight overlay.146 //! Toggles the Telrad sight overlay.
138 void toggleTelrad(bool show);147 void toggleTelrad(bool show);
148 bool getEnableTelrad() const { return flagShowTelrad; }
139 //! Toggles the Telrad sight overlay (overloaded for blind switching).149 //! Toggles the Telrad sight overlay (overloaded for blind switching).
140 void toggleTelrad();150 void toggleTelrad();
141 void enableGuiPanel(bool enable = true);151 void enableGuiPanel(bool enable = true);
@@ -156,6 +166,10 @@
156 bool getFlagUseSemiTransparency(void) const;166 bool getFlagUseSemiTransparency(void) const;
157167
158signals:168signals:
169 void enableOcularChanged(bool value);
170 void enableCrosshairsChanged(bool value);
171 void enableCCDChanged(bool value);
172 void enableTelradChanged(bool value);
159 void selectedCCDChanged();173 void selectedCCDChanged();
160 void selectedOcularChanged();174 void selectedOcularChanged();
161 void selectedTelescopeChanged();175 void selectedTelescopeChanged();
@@ -166,7 +180,7 @@
166 void instrumentChanged();180 void instrumentChanged();
167 void determineMaxEyepieceAngle();181 void determineMaxEyepieceAngle();
168 void setRequireSelection(bool state);182 void setRequireSelection(bool state);
169 void setScaleImageCircle(bool state); 183 void setScaleImageCircle(bool state);
170 void setScreenFOVForCCD();184 void setScreenFOVForCCD();
171 void retranslateGui();185 void retranslateGui();
172 void setStelStyle(const QString& style);186 void setStelStyle(const QString& style);
173187
=== modified file 'plugins/Oculars/src/gui/OcularsGuiPanel.cpp'
--- plugins/Oculars/src/gui/OcularsGuiPanel.cpp 2016-03-04 15:04:20 +0000
+++ plugins/Oculars/src/gui/OcularsGuiPanel.cpp 2016-06-12 13:59:22 +0000
@@ -37,8 +37,8 @@
37#include <QWidget>37#include <QWidget>
3838
39OcularsGuiPanel::OcularsGuiPanel(Oculars* plugin,39OcularsGuiPanel::OcularsGuiPanel(Oculars* plugin,
40 QGraphicsWidget *parent,40 QGraphicsWidget *parent,
41 Qt::WindowFlags wFlags):41 Qt::WindowFlags wFlags):
42 QGraphicsWidget(parent, wFlags),42 QGraphicsWidget(parent, wFlags),
43 ocularsPlugin(plugin),43 ocularsPlugin(plugin),
44 parentWidget(parent),44 parentWidget(parent),
@@ -58,56 +58,49 @@
58 StelApp& stelApp = StelApp::getInstance();58 StelApp& stelApp = StelApp::getInstance();
59 Q_ASSERT(ocularsPlugin->actionShowOcular);59 Q_ASSERT(ocularsPlugin->actionShowOcular);
60 buttonOcular = new StelButton(buttonBar,60 buttonOcular = new StelButton(buttonBar,
61 QPixmap(":/ocular/bt_ocular_on.png"),61 QPixmap(":/ocular/bt_ocular_on.png"),
62 QPixmap(":/ocular/bt_ocular_off.png"),62 QPixmap(":/ocular/bt_ocular_off.png"),
63 QPixmap(),63 QPixmap(),
64 ocularsPlugin->actionShowOcular,64 ocularsPlugin->actionShowOcular,
65 true); //No background65 true); //No background
66 buttonOcular->setToolTip(ocularsPlugin->actionShowOcular->getText());66 buttonOcular->setToolTip(ocularsPlugin->actionShowOcular->getText());
67 buttonOcular->setParentItem(buttonBar);67 buttonOcular->setParentItem(buttonBar);
6868
69 //Hack to avoid buttonOcular being left "checked" if it has been toggled
70 //without any object selected.
71 disconnect(ocularsPlugin->actionShowOcular, SIGNAL(toggled(bool)),
72 ocularsPlugin, SLOT(enableOcular(bool)));
73 connect(ocularsPlugin->actionShowOcular, SIGNAL(toggled(bool)),
74 ocularsPlugin, SLOT(enableOcular(bool)));
75
76 Q_ASSERT(ocularsPlugin->actionShowCrosshairs);69 Q_ASSERT(ocularsPlugin->actionShowCrosshairs);
77 buttonCrosshairs = new StelButton(buttonBar,70 buttonCrosshairs = new StelButton(buttonBar,
78 QPixmap(":/ocular/bt_crosshairs_on.png"),71 QPixmap(":/ocular/bt_crosshairs_on.png"),
79 QPixmap(":/ocular/bt_crosshairs_off.png"),72 QPixmap(":/ocular/bt_crosshairs_off.png"),
80 QPixmap(),73 QPixmap(),
81 ocularsPlugin->actionShowCrosshairs,74 ocularsPlugin->actionShowCrosshairs,
82 true);75 true);
83 buttonCrosshairs->setToolTip(ocularsPlugin->actionShowCrosshairs->getText());76 buttonCrosshairs->setToolTip(ocularsPlugin->actionShowCrosshairs->getText());
84 buttonCrosshairs->setVisible(false);77 buttonCrosshairs->setVisible(false);
8578
86 Q_ASSERT(ocularsPlugin->actionShowSensor);79 Q_ASSERT(ocularsPlugin->actionShowSensor);
87 buttonCcd = new StelButton(buttonBar,80 buttonCcd = new StelButton(buttonBar,
88 QPixmap(":/ocular/bt_sensor_on.png"),81 QPixmap(":/ocular/bt_sensor_on.png"),
89 QPixmap(":/ocular/bt_sensor_off.png"),82 QPixmap(":/ocular/bt_sensor_off.png"),
90 QPixmap(),83 QPixmap(),
91 ocularsPlugin->actionShowSensor,84 ocularsPlugin->actionShowSensor,
92 true);85 true);
93 buttonCcd->setToolTip(ocularsPlugin->actionShowSensor->getText());86 buttonCcd->setToolTip(ocularsPlugin->actionShowSensor->getText());
9487
95 Q_ASSERT(ocularsPlugin->actionShowTelrad);88 Q_ASSERT(ocularsPlugin->actionShowTelrad);
96 buttonTelrad = new StelButton(buttonBar,89 buttonTelrad = new StelButton(buttonBar,
97 QPixmap(":/ocular/bt_telrad_on.png"),90 QPixmap(":/ocular/bt_telrad_on.png"),
98 QPixmap(":/ocular/bt_telrad_off.png"),91 QPixmap(":/ocular/bt_telrad_off.png"),
99 QPixmap(),92 QPixmap(),
100 ocularsPlugin->actionShowTelrad,93 ocularsPlugin->actionShowTelrad,
101 true);94 true);
102 buttonTelrad->setToolTip(ocularsPlugin->actionShowTelrad->getText());95 buttonTelrad->setToolTip(ocularsPlugin->actionShowTelrad->getText());
10396
104 Q_ASSERT(ocularsPlugin->actionConfiguration);97 Q_ASSERT(ocularsPlugin->actionConfiguration);
105 buttonConfiguration = new StelButton(buttonBar,98 buttonConfiguration = new StelButton(buttonBar,
106 QPixmap(":/ocular/bt_settings_on.png"),99 QPixmap(":/ocular/bt_settings_on.png"),
107 QPixmap(":/ocular/bt_settings_off.png"),100 QPixmap(":/ocular/bt_settings_off.png"),
108 QPixmap(),101 QPixmap(),
109 ocularsPlugin->actionConfiguration,102 ocularsPlugin->actionConfiguration,
110 true);103 true);
111 buttonConfiguration->setToolTip(ocularsPlugin->actionConfiguration->getText());104 buttonConfiguration->setToolTip(ocularsPlugin->actionConfiguration->getText());
112105
113 qreal buttonHeight = buttonOcular->boundingRect().height();106 qreal buttonHeight = buttonOcular->boundingRect().height();
@@ -179,73 +172,63 @@
179 QPixmap naOff(":/graphicGui/btTimeForward-off.png");172 QPixmap naOff(":/graphicGui/btTimeForward-off.png");
180 QPixmap nextArrowOff = naOff.scaledToHeight(scale, Qt::SmoothTransformation);173 QPixmap nextArrowOff = naOff.scaledToHeight(scale, Qt::SmoothTransformation);
181174
182 StelAction* defaultAction = new StelAction(this);
183 defaultAction->setCheckable(false);
184 prevOcularButton = new StelButton(ocularControls,175 prevOcularButton = new StelButton(ocularControls,
185 prevArrow,176 prevArrow,
186 prevArrowOff,177 prevArrowOff,
187 QPixmap(),178 QPixmap());
188 defaultAction);
189 prevOcularButton->setToolTip(q_("Previous ocular"));179 prevOcularButton->setToolTip(q_("Previous ocular"));
190 nextOcularButton = new StelButton(ocularControls,180 nextOcularButton = new StelButton(ocularControls,
191 nextArrow,181 nextArrow,
192 nextArrowOff,182 nextArrowOff,
193 QPixmap(),183 QPixmap());
194 defaultAction);
195 nextOcularButton->setToolTip(q_("Next ocular"));184 nextOcularButton->setToolTip(q_("Next ocular"));
196 prevLensButton = new StelButton(lensControls,185 prevLensButton = new StelButton(lensControls,
197 prevArrow,186 prevArrow,
198 prevArrowOff,187 prevArrowOff,
199 QPixmap(),188 QPixmap());
200 defaultAction);
201 prevLensButton->setToolTip(q_("Previous lens"));189 prevLensButton->setToolTip(q_("Previous lens"));
202 nextLensButton = new StelButton(lensControls,190 nextLensButton = new StelButton(lensControls,
203 nextArrow,191 nextArrow,
204 nextArrowOff,192 nextArrowOff,
205 QPixmap(),193 QPixmap());
206 defaultAction);
207 nextLensButton->setToolTip(q_("Next lens"));194 nextLensButton->setToolTip(q_("Next lens"));
208 prevCcdButton = new StelButton(ccdControls,195 prevCcdButton = new StelButton(ccdControls,
209 prevArrow,196 prevArrow,
210 prevArrowOff,197 prevArrowOff,
211 QPixmap(),198 QPixmap());
212 defaultAction);
213 prevCcdButton->setToolTip(q_("Previous CCD frame"));199 prevCcdButton->setToolTip(q_("Previous CCD frame"));
214 nextCcdButton = new StelButton(ccdControls,200 nextCcdButton = new StelButton(ccdControls,
215 nextArrow,201 nextArrow,
216 nextArrowOff,202 nextArrowOff,
217 QPixmap(),203 QPixmap());
218 defaultAction);
219 nextCcdButton->setToolTip(q_("Next CCD frame"));204 nextCcdButton->setToolTip(q_("Next CCD frame"));
220 prevTelescopeButton = new StelButton(telescopeControls,205 prevTelescopeButton = new StelButton(telescopeControls,
221 prevArrow,206 prevArrow,
222 prevArrowOff,207 prevArrowOff,
223 QPixmap(),208 QPixmap());
224 defaultAction);
225 prevTelescopeButton->setToolTip(q_("Previous telescope"));209 prevTelescopeButton->setToolTip(q_("Previous telescope"));
226 nextTelescopeButton = new StelButton(telescopeControls,210 nextTelescopeButton = new StelButton(telescopeControls,
227 nextArrow,211 nextArrow,
228 nextArrowOff,212 nextArrowOff,
229 QPixmap(),213 QPixmap());
230 defaultAction);
231 nextTelescopeButton->setToolTip(q_("Next telescope"));214 nextTelescopeButton->setToolTip(q_("Next telescope"));
232215
233 connect(nextOcularButton, SIGNAL(triggered()),216 connect(nextOcularButton, SIGNAL(triggered()),
234 ocularsPlugin, SLOT(incrementOcularIndex()));217 ocularsPlugin, SLOT(incrementOcularIndex()));
235 connect(nextCcdButton, SIGNAL(triggered()),218 connect(nextCcdButton, SIGNAL(triggered()),
236 ocularsPlugin, SLOT(incrementCCDIndex()));219 ocularsPlugin, SLOT(incrementCCDIndex()));
237 connect(nextTelescopeButton, SIGNAL(triggered()),220 connect(nextTelescopeButton, SIGNAL(triggered()),
238 ocularsPlugin, SLOT(incrementTelescopeIndex()));221 ocularsPlugin, SLOT(incrementTelescopeIndex()));
239 connect(prevOcularButton, SIGNAL(triggered()),222 connect(prevOcularButton, SIGNAL(triggered()),
240 ocularsPlugin, SLOT(decrementOcularIndex()));223 ocularsPlugin, SLOT(decrementOcularIndex()));
241 connect(prevCcdButton, SIGNAL(triggered()),224 connect(prevCcdButton, SIGNAL(triggered()),
242 ocularsPlugin, SLOT(decrementCCDIndex()));225 ocularsPlugin, SLOT(decrementCCDIndex()));
243 connect(prevTelescopeButton, SIGNAL(triggered()),226 connect(prevTelescopeButton, SIGNAL(triggered()),
244 ocularsPlugin, SLOT(decrementTelescopeIndex()));227 ocularsPlugin, SLOT(decrementTelescopeIndex()));
245 connect(nextLensButton, SIGNAL(triggered()),228 connect(nextLensButton, SIGNAL(triggered()),
246 ocularsPlugin, SLOT(incrementLensIndex()));229 ocularsPlugin, SLOT(incrementLensIndex()));
247 connect(prevLensButton, SIGNAL(triggered()),230 connect(prevLensButton, SIGNAL(triggered()),
248 ocularsPlugin, SLOT(decrementLensIndex()));231 ocularsPlugin, SLOT(decrementLensIndex()));
249232
250 QColor cOn(255, 255, 255);233 QColor cOn(255, 255, 255);
251 QColor cOff(102, 102, 102);234 QColor cOff(102, 102, 102);
@@ -256,11 +239,11 @@
256 QPixmap pOff = createPixmapFromText(degrees, degreesW, lineHeight, newFont, cOff);239 QPixmap pOff = createPixmapFromText(degrees, degreesW, lineHeight, newFont, cOff);
257 QPixmap pHover = createPixmapFromText(degrees, degreesW, lineHeight, newFont, cHover);240 QPixmap pHover = createPixmapFromText(degrees, degreesW, lineHeight, newFont, cHover);
258 rotateCcdMinus15Button = new StelButton(ccdControls,241 rotateCcdMinus15Button = new StelButton(ccdControls,
259 pOn,242 pOn,
260 pOff,243 pOff,
261 pHover,244 pHover,
262 defaultAction,245 NULL,
263 true);246 true);
264 rotateCcdMinus15Button->setToolTip(q_("Rotate the sensor frame 15 degrees counterclockwise"));247 rotateCcdMinus15Button->setToolTip(q_("Rotate the sensor frame 15 degrees counterclockwise"));
265248
266 degrees = QString("-5%1").arg(QChar(0x00B0));249 degrees = QString("-5%1").arg(QChar(0x00B0));
@@ -269,10 +252,10 @@
269 pOff = createPixmapFromText(degrees, degreesW, lineHeight, newFont, cOff);252 pOff = createPixmapFromText(degrees, degreesW, lineHeight, newFont, cOff);
270 pHover = createPixmapFromText(degrees, degreesW, lineHeight, newFont, cHover);253 pHover = createPixmapFromText(degrees, degreesW, lineHeight, newFont, cHover);
271 rotateCcdMinus5Button = new StelButton(ccdControls,254 rotateCcdMinus5Button = new StelButton(ccdControls,
272 pOn,255 pOn,
273 pOff,256 pOff,
274 pHover,257 pHover,
275 defaultAction,258 NULL,
276 true);259 true);
277 rotateCcdMinus5Button->setToolTip(q_("Rotate the sensor frame 5 degrees counterclockwise"));260 rotateCcdMinus5Button->setToolTip(q_("Rotate the sensor frame 5 degrees counterclockwise"));
278261
@@ -284,8 +267,8 @@
284 rotateCcdMinus1Button = new StelButton(ccdControls,267 rotateCcdMinus1Button = new StelButton(ccdControls,
285 pOn,268 pOn,
286 pOff,269 pOff,
287 pHover,270 pHover,
288 defaultAction,271 NULL,
289 true);272 true);
290 rotateCcdMinus1Button->setToolTip(q_("Rotate the sensor frame 1 degree counterclockwise"));273 rotateCcdMinus1Button->setToolTip(q_("Rotate the sensor frame 1 degree counterclockwise"));
291274
@@ -295,10 +278,10 @@
295 pOff = createPixmapFromText(degrees, degreesW, lineHeight, newFont, cOff);278 pOff = createPixmapFromText(degrees, degreesW, lineHeight, newFont, cOff);
296 pHover = createPixmapFromText(degrees, degreesW, lineHeight, newFont, cHover);279 pHover = createPixmapFromText(degrees, degreesW, lineHeight, newFont, cHover);
297 resetCcdRotationButton = new StelButton(ccdControls,280 resetCcdRotationButton = new StelButton(ccdControls,
298 pOn,281 pOn,
299 pOff,282 pOff,
300 pHover,283 pHover,
301 defaultAction,284 NULL,
302 true);285 true);
303 resetCcdRotationButton->setToolTip(q_("Reset the sensor frame rotation"));286 resetCcdRotationButton->setToolTip(q_("Reset the sensor frame rotation"));
304287
@@ -311,7 +294,7 @@
311 pOn,294 pOn,
312 pOff,295 pOff,
313 pHover,296 pHover,
314 defaultAction,297 NULL,
315 true);298 true);
316 rotateCcdPlus1Button->setToolTip(q_("Rotate the sensor frame 1 degree clockwise"));299 rotateCcdPlus1Button->setToolTip(q_("Rotate the sensor frame 1 degree clockwise"));
317300
@@ -324,7 +307,7 @@
324 pOn,307 pOn,
325 pOff,308 pOff,
326 pHover,309 pHover,
327 defaultAction,310 NULL,
328 true);311 true);
329 rotateCcdPlus5Button->setToolTip(q_("Rotate the sensor frame 5 degrees clockwise"));312 rotateCcdPlus5Button->setToolTip(q_("Rotate the sensor frame 5 degrees clockwise"));
330313
@@ -336,8 +319,8 @@
336 rotateCcdPlus15Button = new StelButton(ccdControls,319 rotateCcdPlus15Button = new StelButton(ccdControls,
337 pOn,320 pOn,
338 pOff,321 pOff,
339 pHover,322 pHover,
340 defaultAction,323 NULL,
341 true);324 true);
342 rotateCcdPlus15Button->setToolTip(q_("Rotate the sensor frame 15 degrees clockwise"));325 rotateCcdPlus15Button->setToolTip(q_("Rotate the sensor frame 15 degrees clockwise"));
343326
@@ -350,34 +333,34 @@
350 sm->setMapping(rotateCcdPlus15Button, QString("15"));333 sm->setMapping(rotateCcdPlus15Button, QString("15"));
351334
352 connect(rotateCcdMinus15Button, SIGNAL(triggered()),335 connect(rotateCcdMinus15Button, SIGNAL(triggered()),
353 sm, SLOT(map()));336 sm, SLOT(map()));
354 connect(rotateCcdMinus5Button, SIGNAL(triggered()),337 connect(rotateCcdMinus5Button, SIGNAL(triggered()),
355 sm, SLOT(map()));338 sm, SLOT(map()));
356 connect(rotateCcdMinus1Button, SIGNAL(triggered()),339 connect(rotateCcdMinus1Button, SIGNAL(triggered()),
357 sm, SLOT(map()));340 sm, SLOT(map()));
358 connect(rotateCcdPlus1Button, SIGNAL(triggered()),341 connect(rotateCcdPlus1Button, SIGNAL(triggered()),
359 sm, SLOT(map()));342 sm, SLOT(map()));
360 connect(rotateCcdPlus5Button, SIGNAL(triggered()),343 connect(rotateCcdPlus5Button, SIGNAL(triggered()),
361 sm, SLOT(map()));344 sm, SLOT(map()));
362 connect(rotateCcdPlus15Button, SIGNAL(triggered()),345 connect(rotateCcdPlus15Button, SIGNAL(triggered()),
363 sm, SLOT(map()));346 sm, SLOT(map()));
364 connect(resetCcdRotationButton, SIGNAL(triggered()),347 connect(resetCcdRotationButton, SIGNAL(triggered()),
365 ocularsPlugin, SLOT(ccdRotationReset()));348 ocularsPlugin, SLOT(ccdRotationReset()));
366349
367 connect(rotateCcdMinus15Button, SIGNAL(triggered()),350 connect(rotateCcdMinus15Button, SIGNAL(triggered()),
368 this, SLOT(updateCcdControls()));351 this, SLOT(updateCcdControls()));
369 connect(rotateCcdMinus5Button, SIGNAL(triggered()),352 connect(rotateCcdMinus5Button, SIGNAL(triggered()),
370 this, SLOT(updateCcdControls()));353 this, SLOT(updateCcdControls()));
371 connect(rotateCcdMinus1Button, SIGNAL(triggered()),354 connect(rotateCcdMinus1Button, SIGNAL(triggered()),
372 this, SLOT(updateCcdControls()));355 this, SLOT(updateCcdControls()));
373 connect(rotateCcdPlus1Button, SIGNAL(triggered()),356 connect(rotateCcdPlus1Button, SIGNAL(triggered()),
374 this, SLOT(updateCcdControls()));357 this, SLOT(updateCcdControls()));
375 connect(rotateCcdPlus5Button, SIGNAL(triggered()),358 connect(rotateCcdPlus5Button, SIGNAL(triggered()),
376 this, SLOT(updateCcdControls()));359 this, SLOT(updateCcdControls()));
377 connect(rotateCcdPlus15Button, SIGNAL(triggered()),360 connect(rotateCcdPlus15Button, SIGNAL(triggered()),
378 this, SLOT(updateCcdControls()));361 this, SLOT(updateCcdControls()));
379 connect(resetCcdRotationButton, SIGNAL(triggered()),362 connect(resetCcdRotationButton, SIGNAL(triggered()),
380 this, SLOT(updateCcdControls()));363 this, SLOT(updateCcdControls()));
381364
382365
383 //Set the layout and update the size366 //Set the layout and update the size
@@ -395,7 +378,7 @@
395378
396 //Border/background for the widget379 //Border/background for the widget
397 borderPath = new QGraphicsPathItem();380 borderPath = new QGraphicsPathItem();
398 borderPath->setZValue(100); 381 borderPath->setZValue(100);
399 QBrush borderBrush(QColor::fromRgbF(0.22, 0.22, 0.23, 0.2));382 QBrush borderBrush(QColor::fromRgbF(0.22, 0.22, 0.23, 0.2));
400 borderPath->setBrush(borderBrush);383 borderPath->setBrush(borderBrush);
401 QPen borderPen = QPen(QColor::fromRgbF(0.7,0.7,0.7,0.5));384 QPen borderPen = QPen(QColor::fromRgbF(0.7,0.7,0.7,0.5));
@@ -405,17 +388,17 @@
405388
406 updatePosition();389 updatePosition();
407 connect (parentWidget, SIGNAL(geometryChanged()),390 connect (parentWidget, SIGNAL(geometryChanged()),
408 this, SLOT(updatePosition()));391 this, SLOT(updatePosition()));
409392
410 //Connecting other slots393 //Connecting other slots
411 connect(ocularsPlugin, SIGNAL(selectedOcularChanged()),394 connect(ocularsPlugin, SIGNAL(selectedOcularChanged()),
412 this, SLOT(updateOcularControls()));395 this, SLOT(updateOcularControls()));
413 connect(ocularsPlugin, SIGNAL(selectedCCDChanged()),396 connect(ocularsPlugin, SIGNAL(selectedCCDChanged()),
414 this, SLOT(updateCcdControls()));397 this, SLOT(updateCcdControls()));
415 connect(ocularsPlugin, SIGNAL(selectedTelescopeChanged()),398 connect(ocularsPlugin, SIGNAL(selectedTelescopeChanged()),
416 this, SLOT(updateTelescopeControls()));399 this, SLOT(updateTelescopeControls()));
417 connect(ocularsPlugin, SIGNAL(selectedLensChanged()),400 connect(ocularsPlugin, SIGNAL(selectedLensChanged()),
418 this, SLOT(updateTelescopeControls()));401 this, SLOT(updateTelescopeControls()));
419402
420 //Night mode403 //Night mode
421 connect(&stelApp, SIGNAL(colorSchemeChanged(const QString&)),404 connect(&stelApp, SIGNAL(colorSchemeChanged(const QString&)),
@@ -479,7 +462,7 @@
479 QPointF verticalBorderStart = geometry().topLeft();462 QPointF verticalBorderStart = geometry().topLeft();
480 QPointF horizontalBorderEnd = geometry().bottomRight();463 QPointF horizontalBorderEnd = geometry().bottomRight();
481 QPointF cornerArcStart(verticalBorderStart.x(),464 QPointF cornerArcStart(verticalBorderStart.x(),
482 horizontalBorderEnd.y() - cornerRadius);465 horizontalBorderEnd.y() - cornerRadius);
483 newBorderPath.moveTo(verticalBorderStart);466 newBorderPath.moveTo(verticalBorderStart);
484 newBorderPath.lineTo(cornerArcStart);467 newBorderPath.lineTo(cornerArcStart);
485 newBorderPath.arcTo(cornerArcStart.x(), cornerArcStart.y(), cornerRadius, cornerRadius, 180, 90);468 newBorderPath.arcTo(cornerArcStart.x(), cornerArcStart.y(), cornerRadius, cornerRadius, 180, 90);
@@ -552,7 +535,7 @@
552 QString apparentFovString = QString::number(apparentFov);535 QString apparentFovString = QString::number(apparentFov);
553 apparentFovString.append(QChar(0x00B0));// Degree sign536 apparentFovString.append(QChar(0x00B0));// Degree sign
554 QString apparentFovLabel = QString(q_("Ocular aFOV: %1"))537 QString apparentFovLabel = QString(q_("Ocular aFOV: %1"))
555 .arg(apparentFovString);538 .arg(apparentFovString);
556 fieldOcularAfov->setPlainText(apparentFovLabel);539 fieldOcularAfov->setPlainText(apparentFovLabel);
557 fieldOcularAfov->setToolTip(q_("Apparent field of view of the ocular"));540 fieldOcularAfov->setToolTip(q_("Apparent field of view of the ocular"));
558 fieldOcularAfov->setPos(posX, posY);541 fieldOcularAfov->setPos(posX, posY);
@@ -637,8 +620,8 @@
637620
638 //Get the name621 //Get the name
639 int index = ocularsPlugin->selectedCCDIndex;622 int index = ocularsPlugin->selectedCCDIndex;
640 CCD* ccd = ocularsPlugin->ccds[index]; 623 CCD* ccd = ocularsPlugin->ccds[index];
641 Q_ASSERT(ccd); 624 Q_ASSERT(ccd);
642 QString name = ccd->name();625 QString name = ccd->name();
643 QString fullName;626 QString fullName;
644 if (name.isEmpty())627 if (name.isEmpty())
@@ -801,7 +784,7 @@
801 posY = 0.;784 posY = 0.;
802 widgetHeight = 0.;785 widgetHeight = 0.;
803786
804 fieldMagnification->setToolTip(q_("Magnification provided by these binoculars")); 787 fieldMagnification->setToolTip(q_("Magnification provided by these binoculars"));
805 fieldFov->setToolTip(q_("Actual field of view provided by these binoculars"));788 fieldFov->setToolTip(q_("Actual field of view provided by these binoculars"));
806 fieldExitPupil->setToolTip(q_("Exit pupil provided by these binoculars"));789 fieldExitPupil->setToolTip(q_("Exit pupil provided by these binoculars"));
807 }790 }
@@ -811,15 +794,15 @@
811 nextTelescopeButton->setVisible(true);794 nextTelescopeButton->setVisible(true);
812 fieldTelescopeName->setVisible(true);795 fieldTelescopeName->setVisible(true);
813796
814 fieldMagnification->setToolTip(q_("Magnification provided by this ocular/lens/telescope combination")); 797 fieldMagnification->setToolTip(q_("Magnification provided by this ocular/lens/telescope combination"));
815 fieldFov->setToolTip(q_("Actual field of view provided by this ocular/lens/telescope combination"));798 fieldFov->setToolTip(q_("Actual field of view provided by this ocular/lens/telescope combination"));
816 fieldExitPupil->setToolTip(q_("Exit pupil provided by this ocular/lens/telescope combination"));799 fieldExitPupil->setToolTip(q_("Exit pupil provided by this ocular/lens/telescope combination"));
817 }800 }
818801
819 //WTF? Rounding?802 //WTF? Rounding?
820 double magnification = ((int)(ocular->magnification(telescope, lens) * 10.0)) / 10.0;803 double magnification = ((int)(ocular->magnification(telescope, lens) * 10.0)) / 10.0;
821 QString magnificationString = QString::number(magnification); 804 QString magnificationString = QString::number(magnification);
822 magnificationString.append(QChar(0x00D7)); 805 magnificationString.append(QChar(0x00D7));
823 QString magnificationLabel = QString(q_("Magnification: %1")).arg(magnificationString);806 QString magnificationLabel = QString(q_("Magnification: %1")).arg(magnificationString);
824 fieldMagnification->setPlainText(magnificationLabel);807 fieldMagnification->setPlainText(magnificationLabel);
825 fieldMagnification->setPos(posX, posY);808 fieldMagnification->setPos(posX, posY);
@@ -963,7 +946,7 @@
963void OcularsGuiPanel::updateMainButtonsPositions()946void OcularsGuiPanel::updateMainButtonsPositions()
964{947{
965 Q_ASSERT(buttonOcular);948 Q_ASSERT(buttonOcular);
966 Q_ASSERT(buttonCrosshairs); 949 Q_ASSERT(buttonCrosshairs);
967 Q_ASSERT(buttonCcd);950 Q_ASSERT(buttonCcd);
968 Q_ASSERT(buttonTelrad);951 Q_ASSERT(buttonTelrad);
969 Q_ASSERT(buttonConfiguration);952 Q_ASSERT(buttonConfiguration);
@@ -984,7 +967,7 @@
984 {967 {
985 qreal parentWidth = buttonOcular->parentItem()->boundingRect().width();968 qreal parentWidth = buttonOcular->parentItem()->boundingRect().width();
986 int nGaps = n - 1;//n buttons have n-1 gaps969 int nGaps = n - 1;//n buttons have n-1 gaps
987 spacing = qRound((parentWidth-width)/nGaps);970 spacing = qRound((parentWidth-width)/nGaps);
988 }971 }
989 buttonOcular->setPos(posX, posY);972 buttonOcular->setPos(posX, posY);
990 posX += buttonOcular->getButtonPixmapWidth() + spacing;973 posX += buttonOcular->getButtonPixmapWidth() + spacing;
@@ -1067,11 +1050,11 @@
1067}1050}
10681051
1069QPixmap OcularsGuiPanel::createPixmapFromText(const QString& text,1052QPixmap OcularsGuiPanel::createPixmapFromText(const QString& text,
1070 int width,1053 int width,
1071 int height,1054 int height,
1072 const QFont& font,1055 const QFont& font,
1073 const QColor& textColor,1056 const QColor& textColor,
1074 const QColor& backgroundColor)1057 const QColor& backgroundColor)
1075{1058{
1076 if (width <= 0 || height <=0) {1059 if (width <= 0 || height <=0) {
1077 return QPixmap();1060 return QPixmap();
@@ -1088,8 +1071,8 @@
1088 painter.setFont(font);1071 painter.setFont(font);
1089 painter.setPen(QPen(textColor));1072 painter.setPen(QPen(textColor));
1090 painter.drawText(0, 0, width, height,1073 painter.drawText(0, 0, width, height,
1091 Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextSingleLine,1074 Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextSingleLine,
1092 text);1075 text);
10931076
1094 return pixmap;1077 return pixmap;
1095}1078}
10961079
=== added directory 'plugins/RemoteControl'
=== added file 'plugins/RemoteControl/CMakeLists.txt'
--- plugins/RemoteControl/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ plugins/RemoteControl/CMakeLists.txt 2016-06-12 13:59:22 +0000
@@ -0,0 +1,46 @@
1# This is the cmake config file for the RemoteControl plugin
2SET(REMOTECONTROL_VERSION "0.0.1")
3ADD_DEFINITIONS(-DREMOTECONTROL_VERSION="${REMOTECONTROL_VERSION}")
4SET(REMOTECONTROL_WEBROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/webroot/")
5ADD_DEFINITIONS(-DREMOTECONTROL_WEBROOT_PATH="${REMOTECONTROL_WEBROOT_PATH}")
6
7ADD_SUBDIRECTORY( src )
8
9# Custom target for updating the translationdata.js
10find_package(PythonInterp)
11
12if(PYTHON_EXECUTABLE)
13 add_custom_target(RemoteControl-update-translationdata
14 COMMAND ${PYTHON_EXECUTABLE} util/update_translationdata.py
15 ${PROJECT_SOURCE_DIR}/po/stellarium-remotecontrol/stellarium-remotecontrol-js.pot ${REMOTECONTROL_WEBROOT_PATH}/js/translationdata.js
16 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
17 COMMENT "Updating RemoteControl translation data"
18 VERBATIM
19 )
20
21 add_dependencies(RemoteControl-update-translationdata generate-pot-stellarium-remotecontrol-js)
22endif()
23
24IF(APPLE)
25 SET(CMAKE_INSTALL_PREFIX $ENV{HOME}/Library/Application\ Support/Stellarium)
26ElSE(APPLE)
27 SET(CMAKE_INSTALL_PREFIX $ENV{HOME}/.stellarium)
28ENDIF(APPLE)
29INSTALL(FILES DESTINATION "modules/RemoteControl")
30
31
32########### install files ###############
33# install webroot
34INSTALL(DIRECTORY ${REMOTECONTROL_WEBROOT_PATH} DESTINATION share/${PACKAGE}/webroot FILES_MATCHING
35 PATTERN "*.png"
36 PATTERN "*.gif"
37 PATTERN "*.html"
38 PATTERN "*.js"
39 PATTERN "*.css"
40 PATTERN "*.eot"
41 PATTERN "*.svg"
42 PATTERN "*.ttf"
43 PATTERN "*.woff"
44 PATTERN "*.woff2"
45 PATTERN "translate_files"
46 PATTERN "*.ico")
0\ No newline at end of file47\ No newline at end of file
148
=== added file 'plugins/RemoteControl/COPYING'
--- plugins/RemoteControl/COPYING 1970-01-01 00:00:00 +0000
+++ plugins/RemoteControl/COPYING 2016-06-12 13:59:22 +0000
@@ -0,0 +1,340 @@
1 GNU GENERAL PUBLIC LICENSE
2 Version 2, June 1991
3
4 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
5 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
6 Everyone is permitted to copy and distribute verbatim copies
7 of this license document, but changing it is not allowed.
8
9 Preamble
10
11 The licenses for most software are designed to take away your
12freedom to share and change it. By contrast, the GNU General Public
13License is intended to guarantee your freedom to share and change free
14software--to make sure the software is free for all its users. This
15General Public License applies to most of the Free Software
16Foundation's software and to any other program whose authors commit to
17using it. (Some other Free Software Foundation software is covered by
18the GNU Library General Public License instead.) You can apply it to
19your programs, too.
20
21 When we speak of free software, we are referring to freedom, not
22price. Our General Public Licenses are designed to make sure that you
23have the freedom to distribute copies of free software (and charge for
24this service if you wish), that you receive source code or can get it
25if you want it, that you can change the software or use pieces of it
26in new free programs; and that you know you can do these things.
27
28 To protect your rights, we need to make restrictions that forbid
29anyone to deny you these rights or to ask you to surrender the rights.
30These restrictions translate to certain responsibilities for you if you
31distribute copies of the software, or if you modify it.
32
33 For example, if you distribute copies of such a program, whether
34gratis or for a fee, you must give the recipients all the rights that
35you have. You must make sure that they, too, receive or can get the
36source code. And you must show them these terms so they know their
37rights.
38
39 We protect your rights with two steps: (1) copyright the software, and
40(2) offer you this license which gives you legal permission to copy,
41distribute and/or modify the software.
42
43 Also, for each author's protection and ours, we want to make certain
44that everyone understands that there is no warranty for this free
45software. If the software is modified by someone else and passed on, we
46want its recipients to know that what they have is not the original, so
47that any problems introduced by others will not reflect on the original
48authors' reputations.
49
50 Finally, any free program is threatened constantly by software
51patents. We wish to avoid the danger that redistributors of a free
52program will individually obtain patent licenses, in effect making the
53program proprietary. To prevent this, we have made it clear that any
54patent must be licensed for everyone's free use or not licensed at all.
55
56 The precise terms and conditions for copying, distribution and
57modification follow.
58
059
60 GNU GENERAL PUBLIC LICENSE
61 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
62
63 0. This License applies to any program or other work which contains
64a notice placed by the copyright holder saying it may be distributed
65under the terms of this General Public License. The "Program", below,
66refers to any such program or work, and a "work based on the Program"
67means either the Program or any derivative work under copyright law:
68that is to say, a work containing the Program or a portion of it,
69either verbatim or with modifications and/or translated into another
70language. (Hereinafter, translation is included without limitation in
71the term "modification".) Each licensee is addressed as "you".
72
73Activities other than copying, distribution and modification are not
74covered by this License; they are outside its scope. The act of
75running the Program is not restricted, and the output from the Program
76is covered only if its contents constitute a work based on the
77Program (independent of having been made by running the Program).
78Whether that is true depends on what the Program does.
79
80 1. You may copy and distribute verbatim copies of the Program's
81source code as you receive it, in any medium, provided that you
82conspicuously and appropriately publish on each copy an appropriate
83copyright notice and disclaimer of warranty; keep intact all the
84notices that refer to this License and to the absence of any warranty;
85and give any other recipients of the Program a copy of this License
86along with the Program.
87
88You may charge a fee for the physical act of transferring a copy, and
89you may at your option offer warranty protection in exchange for a fee.
90
91 2. You may modify your copy or copies of the Program or any portion
92of it, thus forming a work based on the Program, and copy and
93distribute such modifications or work under the terms of Section 1
94above, provided that you also meet all of these conditions:
95
96 a) You must cause the modified files to carry prominent notices
97 stating that you changed the files and the date of any change.
98
99 b) You must cause any work that you distribute or publish, that in
100 whole or in part contains or is derived from the Program or any
101 part thereof, to be licensed as a whole at no charge to all third
102 parties under the terms of this License.
103
104 c) If the modified program normally reads commands interactively
105 when run, you must cause it, when started running for such
106 interactive use in the most ordinary way, to print or display an
107 announcement including an appropriate copyright notice and a
108 notice that there is no warranty (or else, saying that you provide
109 a warranty) and that users may redistribute the program under
110 these conditions, and telling the user how to view a copy of this
111 License. (Exception: if the Program itself is interactive but
112 does not normally print such an announcement, your work based on
113 the Program is not required to print an announcement.)
114
1115
116These requirements apply to the modified work as a whole. If
117identifiable sections of that work are not derived from the Program,
118and can be reasonably considered independent and separate works in
119themselves, then this License, and its terms, do not apply to those
120sections when you distribute them as separate works. But when you
121distribute the same sections as part of a whole which is a work based
122on the Program, the distribution of the whole must be on the terms of
123this License, whose permissions for other licensees extend to the
124entire whole, and thus to each and every part regardless of who wrote it.
125
126Thus, it is not the intent of this section to claim rights or contest
127your rights to work written entirely by you; rather, the intent is to
128exercise the right to control the distribution of derivative or
129collective works based on the Program.
130
131In addition, mere aggregation of another work not based on the Program
132with the Program (or with a work based on the Program) on a volume of
133a storage or distribution medium does not bring the other work under
134the scope of this License.
135
136 3. You may copy and distribute the Program (or a work based on it,
137under Section 2) in object code or executable form under the terms of
138Sections 1 and 2 above provided that you also do one of the following:
139
140 a) Accompany it with the complete corresponding machine-readable
141 source code, which must be distributed under the terms of Sections
142 1 and 2 above on a medium customarily used for software interchange; or,
143
144 b) Accompany it with a written offer, valid for at least three
145 years, to give any third party, for a charge no more than your
146 cost of physically performing source distribution, a complete
147 machine-readable copy of the corresponding source code, to be
148 distributed under the terms of Sections 1 and 2 above on a medium
149 customarily used for software interchange; or,
150
151 c) Accompany it with the information you received as to the offer
152 to distribute corresponding source code. (This alternative is
153 allowed only for noncommercial distribution and only if you
154 received the program in object code or executable form with such
155 an offer, in accord with Subsection b above.)
156
157The source code for a work means the preferred form of the work for
158making modifications to it. For an executable work, complete source
159code means all the source code for all modules it contains, plus any
160associated interface definition files, plus the scripts used to
161control compilation and installation of the executable. However, as a
162special exception, the source code distributed need not include
163anything that is normally distributed (in either source or binary
164form) with the major components (compiler, kernel, and so on) of the
165operating system on which the executable runs, unless that component
166itself accompanies the executable.
167
168If distribution of executable or object code is made by offering
169access to copy from a designated place, then offering equivalent
170access to copy the source code from the same place counts as
171distribution of the source code, even though third parties are not
172compelled to copy the source along with the object code.
173
2174
175 4. You may not copy, modify, sublicense, or distribute the Program
176except as expressly provided under this License. Any attempt
177otherwise to copy, modify, sublicense or distribute the Program is
178void, and will automatically terminate your rights under this License.
179However, parties who have received copies, or rights, from you under
180this License will not have their licenses terminated so long as such
181parties remain in full compliance.
182
183 5. You are not required to accept this License, since you have not
184signed it. However, nothing else grants you permission to modify or
185distribute the Program or its derivative works. These actions are
186prohibited by law if you do not accept this License. Therefore, by
187modifying or distributing the Program (or any work based on the
188Program), you indicate your acceptance of this License to do so, and
189all its terms and conditions for copying, distributing or modifying
190the Program or works based on it.
191
192 6. Each time you redistribute the Program (or any work based on the
193Program), the recipient automatically receives a license from the
194original licensor to copy, distribute or modify the Program subject to
195these terms and conditions. You may not impose any further
196restrictions on the recipients' exercise of the rights granted herein.
197You are not responsible for enforcing compliance by third parties to
198this License.
199
200 7. If, as a consequence of a court judgment or allegation of patent
201infringement or for any other reason (not limited to patent issues),
202conditions are imposed on you (whether by court order, agreement or
203otherwise) that contradict the conditions of this License, they do not
204excuse you from the conditions of this License. If you cannot
205distribute so as to satisfy simultaneously your obligations under this
206License and any other pertinent obligations, then as a consequence you
207may not distribute the Program at all. For example, if a patent
208license would not permit royalty-free redistribution of the Program by
209all those who receive copies directly or indirectly through you, then
210the only way you could satisfy both it and this License would be to
211refrain entirely from distribution of the Program.
212
213If any portion of this section is held invalid or unenforceable under
214any particular circumstance, the balance of the section is intended to
215apply and the section as a whole is intended to apply in other
216circumstances.
217
218It is not the purpose of this section to induce you to infringe any
219patents or other property right claims or to contest validity of any
220such claims; this section has the sole purpose of protecting the
221integrity of the free software distribution system, which is
222implemented by public license practices. Many people have made
223generous contributions to the wide range of software distributed
224through that system in reliance on consistent application of that
225system; it is up to the author/donor to decide if he or she is willing
226to distribute software through any other system and a licensee cannot
227impose that choice.
228
229This section is intended to make thoroughly clear what is believed to
230be a consequence of the rest of this License.
231
3232
233 8. If the distribution and/or use of the Program is restricted in
234certain countries either by patents or by copyrighted interfaces, the
235original copyright holder who places the Program under this License
236may add an explicit geographical distribution limitation excluding
237those countries, so that distribution is permitted only in or among
238countries not thus excluded. In such case, this License incorporates
239the limitation as if written in the body of this License.
240
241 9. The Free Software Foundation may publish revised and/or new versions
242of the General Public License from time to time. Such new versions will
243be similar in spirit to the present version, but may differ in detail to
244address new problems or concerns.
245
246Each version is given a distinguishing version number. If the Program
247specifies a version number of this License which applies to it and "any
248later version", you have the option of following the terms and conditions
249either of that version or of any later version published by the Free
250Software Foundation. If the Program does not specify a version number of
251this License, you may choose any version ever published by the Free Software
252Foundation.
253
254 10. If you wish to incorporate parts of the Program into other free
255programs whose distribution conditions are different, write to the author
256to ask for permission. For software which is copyrighted by the Free
257Software Foundation, write to the Free Software Foundation; we sometimes
258make exceptions for this. Our decision will be guided by the two goals
259of preserving the free status of all derivatives of our free software and
260of promoting the sharing and reuse of software generally.
261
262 NO WARRANTY
263
264 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
265FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
266OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
267PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
268OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
269MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
270TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
271PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
272REPAIR OR CORRECTION.
273
274 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
275WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
276REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
277INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
278OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
279TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
280YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
281PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
282POSSIBILITY OF SUCH DAMAGES.
283
284 END OF TERMS AND CONDITIONS
285
4286
287 How to Apply These Terms to Your New Programs
288
289 If you develop a new program, and you want it to be of the greatest
290possible use to the public, the best way to achieve this is to make it
291free software which everyone can redistribute and change under these terms.
292
293 To do so, attach the following notices to the program. It is safest
294to attach them to the start of each source file to most effectively
295convey the exclusion of warranty; and each file should have at least
296the "copyright" line and a pointer to where the full notice is found.
297
298 <one line to give the program's name and a brief idea of what it does.>
299 Copyright (C) <year> <name of author>
300
301 This program is free software; you can redistribute it and/or modify
302 it under the terms of the GNU General Public License as published by
303 the Free Software Foundation; either version 2 of the License, or
304 (at your option) any later version.
305
306 This program is distributed in the hope that it will be useful,
307 but WITHOUT ANY WARRANTY; without even the implied warranty of
308 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
309 GNU General Public License for more details.
310
311 You should have received a copy of the GNU General Public License
312 along with this program; if not, write to the Free Software
313 Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
314
315
316Also add information on how to contact you by electronic and paper mail.
317
318If the program is interactive, make it output a short notice like this
319when it starts in an interactive mode:
320
321 Gnomovision version 69, Copyright (C) year name of author
322 Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
323 This is free software, and you are welcome to redistribute it
324 under certain conditions; type `show c' for details.
325
326The hypothetical commands `show w' and `show c' should show the appropriate
327parts of the General Public License. Of course, the commands you use may
328be called something other than `show w' and `show c'; they could even be
329mouse-clicks or menu items--whatever suits your program.
330
331You should also get your employer (if you work as a programmer) or your
332school, if any, to sign a "copyright disclaimer" for the program, if
333necessary. Here is a sample; alter the names:
334
335 Yoyodyne, Inc., hereby disclaims all copyright interest in the program
336 `Gnomovision' (which makes passes at compilers) written by James Hacker.
337
338 <signature of Ty Coon>, 1 April 1989
339 Ty Coon, President of Vice
340
341This General Public License does not permit incorporating your program into
342proprietary programs. If your program is a subroutine library, you may
343consider it more useful to permit linking proprietary applications with the
344library. If this is what you want to do, use the GNU Library General
345Public License instead of this License.
5346
=== added file 'plugins/RemoteControl/RemoteControl.qrc'
--- plugins/RemoteControl/RemoteControl.qrc 1970-01-01 00:00:00 +0000
+++ plugins/RemoteControl/RemoteControl.qrc 2016-06-12 13:59:22 +0000
@@ -0,0 +1,6 @@
1<RCC>
2 <qresource prefix="/RemoteControl">
3 <file>resources/bt_remote_off.png</file>
4 <file>resources/bt_remote_on.png</file>
5 </qresource>
6</RCC>
07
=== added directory 'plugins/RemoteControl/doc'
=== added file 'plugins/RemoteControl/doc/qtwebapp.doxygen'
--- plugins/RemoteControl/doc/qtwebapp.doxygen 1970-01-01 00:00:00 +0000
+++ plugins/RemoteControl/doc/qtwebapp.doxygen 2016-06-12 13:59:22 +0000
@@ -0,0 +1,35 @@
1/*
2 * Stellarium
3 * Copyright (C) 2016 Florian Schaukowitsch
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20/*!
21
22@defgroup qtWebApp QtWebApp library
23
24The QtWebApp library is developed by Stefan Frings (http://stefanfrings.de/qtwebapp/index-en.html).
25It is used by the Stellarium \ref remoteControl to provide the HTTP server that serves the plugin's API.
26
27Some changes have been made to the library to fit it better into Stellarium. The main differences are:
28- The settings are no longer specified using QSettings, but with configuration structs (HttpListenerSettings, StaticFileControllerSettings, etc)
29- The template engine supports translating strings at runtime through tags in pseudo-PHP style instead of just different files per language (ITemplateTranslationProvider, Template::translate)
30- The Content-Type detection of the StaticFileController has been extended to use QMimeDatabase, if required.
31
32@author Stefan Frings, Florian Schaukowitsch
33@copyright GNU Lesser General Public License (https://www.gnu.org/licenses/lgpl.html)
34
35*/
036
=== added file 'plugins/RemoteControl/doc/remoteControl.doxygen'
--- plugins/RemoteControl/doc/remoteControl.doxygen 1970-01-01 00:00:00 +0000
+++ plugins/RemoteControl/doc/remoteControl.doxygen 2016-06-12 13:59:22 +0000
@@ -0,0 +1,61 @@
1/*
2 * Stellarium
3 * Copyright (C) 2016 Florian Schaukowitsch
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20/*!
21@defgroup remoteControl Remote Control Plug-in
22@brief Control Stellarium through your web browser! For more information, see @ref remoteControlDoc.
23
24@page remoteControlDoc Remote Control Plug-in documentation
25The %RemoteControl plugin provides a remote control using a webserver interface, usable for single or even synchronized cluster of clients (via the RemoteSync plugin).
26You can simply connect via web browser to a
27configurable port (default: 8090) of your computer. To use it locally, you can use
28http://localhost:8090[/index.html]
29or for a slightly modified GUI which may be better suited for smaller 7inch screens, try
30http://localhost:8090/tablet7in.html.
31Your 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>).
32
33The 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
34some knowledge of HTML, CSS and maybe JavaScript (not necessary for basic functionality, only when more complex additions are required).
35Alternative or derived HTML control GUIs must be placed into the same folder,
36the web server for now cannot read data from the private Stellarium user directory (<tt>~/.stellarium</tt>, <tt>\%APPDATA\%\\stellarium</tt>).
37
38This plugin makes extensive use of the StelProperty system introduced with it. This allows not only to trigger actions,
39but also set QVariant values, which is enough to control many things in the program.
40A few dedicated modules have been implemented closely following the existing GUI for view motion, location setting,
41landscape and skyculture selection, searching objects, etc.
42It is also possible to define interfaces that control plugins, and dynamically show them only when the plugin is enabled.
43
44Because the API is based on simple HTTP calls, it can also be called from command-line clients. For example,
45to execute the script "double_stars.ssc", one could use one of the following lines:
46@code
47wget -q --post-data 'id=double_stars.ssc' http://localhost:8090/api/scripts/run >/dev/null 2>&amp;1
48curl --data 'id=double_stars.ssc' http://localhost:8090/api/scripts/run >/dev/null 2>&amp;1
49curl -d 'id=double_stars.ssc' http://localhost:8090/api/scripts/run >/dev/null 2>&amp;1
50@endcode
51This allows triggering automatic show setups for museums etc.
52
53The entry point of the plugin is the RemoteControl class.
54- 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.
55- To see how the web interface works (i.e. if you want to modify it or add new controls), see @subpage remoteControlWeb.
56
57@author Florian Schaukowitsch, Georg Zotti
58@note This plugin includes parts of the \ref qtWebApp by Stefan Frings, used under the LGPL
59@note This plugin has been developed as project of ESA SoCiS 2015 (http://sophia.estec.esa.int/socis/)
60
61*/
062
=== added file 'plugins/RemoteControl/doc/remoteControlApi.doxygen'
--- plugins/RemoteControl/doc/remoteControlApi.doxygen 1970-01-01 00:00:00 +0000
+++ plugins/RemoteControl/doc/remoteControlApi.doxygen 2016-06-12 13:59:22 +0000
@@ -0,0 +1,461 @@
1/*
2 * Stellarium
3 * Copyright (C) 2016 Florian Schaukowitsch
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20/*!
21
22\page remoteControlApi %RemoteControl plugin HTTP API description
23
24The \ref remoteControl "RemoteControl plugin" provides an HTTP-based interface to Stellarium, implemented on the server-side through implementations of AbstractAPIService.
25The APIController maintains the list of registered services, and dispatches HTTP requests to the right service.
26The API is accessible under the server path `/api/`. For example, if you have the server running on the default port of 8090,
27you can access the operation \ref rcObjectServiceFind of the ObjectService to look for objects with \c moon in their name by accessing
28\code
29http://localhost:8090/api/objects/find?str=moon
30|____________________|___|_______|____|_______|
31 | | | | |------ Standard HTTP query string for parameters (key=value)
32 | | | |------------ find operation (defined by service)
33 | | |------------------- service (e.g. ObjectService)
34 | |------------------------- API prefix (always /api/)
35 |-------------------------------------- server access (http://host:port)
36\endcode
37
38Instead of the \ref remoteControlWeb "HTTP remote interface" you can also use tools like <a href="https://curl.haxx.se/">cURL</a>
39to access the API remotely. For POST operations, you would use the flag \c -d to pass parameters. For GET operations, you should use
40the additional flag \c -G if parameters are required. Examples:
41@code{.sh}
42# retrieve info about the script "double_stars.ssc" with a GET request
43curl -G -d 'id=double_stars.ssc' http://localhost:8090/api/scripts/info
44# run the script "double_stars.ssc" with a POST request
45curl -d 'id=double_stars.ssc' http://localhost:8090/api/scripts/run
46@endcode
47
48If 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.
49HTTPS configuration is currently not implemented, even if the underlying \ref qtWebApp would allow it.
50
51Most operations return data in the <a href="http://www.json.org/">JSON</a> format, allowing it to be easily used in web applications.
52The format of the returned JSON data is described for each operation below.
53Some operations return plain text if only simple data is requested, or to confirm the success of an operation:
54to 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.
55Other operations may return HTML or even image data, you can check the returned Content-Type header if you are not sure what to expect.
56
57\tableofcontents
58
59\section rcExtendApi Extending the API
60
61The simplest way to expose new data through the API is by using the StelProperty system for a property you want to access.
62In 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).
63You do not need to change/implement a new service in any way for this case.
64
65If you want to expose more complex behaviour, you may need to implement your own AbstractAPIService and register it with the APIController.
66\todo Find out how to do this in plugin code
67
68\section rcApiReference API reference
69
70The default services are registered in the RequestHandler::RequestHandler() constructor. They are:
71
72Service | Path | Description
73--------------------- | --------------------------------------------------- | ------------------------
74MainService | \ref rcMainService "main" | \copybrief MainService
75ObjectService | \ref rcObjectService "objects" | \copybrief ObjectService
76ScriptService | \ref rcScriptService "scripts" | \copybrief ScriptService
77SimbadService | \ref rcSimbadService "simbad" | \copybrief SimbadService
78StelActionService | \ref rcStelActionService "stelaction" | \copybrief StelActionService
79StelPropertyService | \ref rcStelPropertyService "stelproperty" | \copybrief StelPropertyService
80LocationService | \ref rcLocationService "location" | \copybrief LocationService
81LocationSearchService | \ref rcLocationSearchService "locationsearch" | \copybrief LocationSearchService
82ViewService | \ref rcViewService "view" | \copybrief ViewService
83
84\subsection rcMainService MainService operations (/api/main/)
85\subsubsection rcMainServiceGET GET operations
86Implemented by MainService::getImpl
87
88\paragraph rcMainServiceStatus status
89Parameters: <tt>[actionId (Number)] [propId (Number)]</tt>\n
90This 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:
91\code{.js}
92{
93 //current location information, see StelLocation
94 location : {
95 name,
96 role,
97 planet,
98 latitude,
99 longitude,
100 altitude,
101 country,
102 state,
103 landscapeKey
104 },
105 //current time information
106 time : {
107 jday, //current Julian day
108 deltaT, //current deltaT as determined by the current dT algorithm
109 gmtShift, //the timezone shift to GMT
110 timeZone, //the timezone name
111 utc, //the time in UTC time zone as ISO8601 time string
112 local, //the time in local time zone as ISO8601 time string
113 isTimeNow, //if true, the Stellarium time equals the current real-world time
114 timerate //the current time rate (in secs)
115 },
116 selectioninfo, //string that contains the information of the currently selected object, as returned by StelObject::getInfoString
117 view : {
118 fov //current FOV
119 },
120
121 //the following is only inserted if an actionId parameter was given
122 //see below for more info
123 actionChanges : {
124 id, //currently valid action id, the interface should update its own id to this value
125 changes : {
126 //a list of boolean actions that changed since the actionId parameter
127 <actionName> : <actionValue>
128 }
129 },
130 //the following is only inserted if an propId parameter was given
131 //see below for more info
132 propertyChanges : {
133 id, //currently valid prop id, the interface should update its own id to this value
134 changes : {
135 //a list of properties that changed since the propId parameter
136 <propName> : <propValue>
137 }
138 }
139}
140\endcode
141
142The \c actionChanges and \c propertyChanges sections allow a remote interface to track boolean StelAction and/or StelProperty changes.
143On the initial poll, you should pass -2 as \p propId and \p actionId. This indicates to the service that you want a full
144list of properties/actions and their current values. When receiving the answer, you should set your local \p propId /\p actionId to the id
145contained in \c actionChanges and \c propertyChanges, and re-send it with the next request as parameter again.
146This allows the MainService to find out which changes must be sent to you (it maintains a queue of action/property changes internally, incrementing
147the ID with each change), and you only have to process the differences instead of everything.
148
149\paragraph rcMainServicePlugins plugins
150Returns the list of all known plugins, as a JSON object of format:
151\code{.js}
152{
153 //list of known plugins, in format:
154 <pluginName> : {
155 loadAtStartup, //if to load the plugin at startup
156 loaded, //if the plugin is currently loaded
157 //corresponds to the StelPluginInfo of the plugin
158 info : {
159 authors,
160 contact,
161 description,
162 displayedName,
163 startByDefault,
164 version
165 }
166 }
167}
168\endcode
169
170\subsubsection rcMainServicePOST POST operations
171Implemented by MainService::postImpl
172
173\paragraph rcMainServiceTime time
174Parameters: <tt>time (Number) timerate (Number)</tt>\n
175Sets the current Stellarium simulation time and/or timerate. The \p time parameter defines the current time (Julian day) as passed to StelCore::setJD.
176The \p timerate parameter allows to change the speed at which the simulation time moves (in JDay/sec) as passed to StelCore::setTimeRate.
177
178\paragraph rcMainServiceFocus focus
179Parameters: <tt>[target (String) | position (JSON Number Array of size 3, i.e. Vec3d)]</tt>\n
180Sets the current app focus/selection. If no parameters are given, the current selection is cleared.
181If 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).
182If the \p position parameter is used, it is interpreted as a coordinate in the J2000 frame, and focused using StelMovementMgr::moveToJ2000
183
184\paragraph rcMainServiceMove move
185Parameters: <tt>x (Number) y (Number)</tt>\n
186Allows viewport movement, like using the arrow keys in the main program. This allows interfaces to create a "virtual joystick" to move the view manually.
187This operation defines the intended move direction. \p x and \p y define the intended
188move 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.
189This operation works in conjunction with the update() method - until the movement is stopped
190(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.
191
192\paragraph rcMainServiceFov fov
193Parameters: <tt>fov (Number)</tt>\n
194Sets the current field-of-view using StelCore::setFov
195
196\subsection rcObjectService ObjectService operations (/api/objects/)
197\subsubsection rcObjectServiceGET GET operations
198Implemented by ObjectService::getImpl
199
200\paragraph rcObjectServiceFind find
201Parameters: <tt>str (String)</tt>\n
202Finds objects which match the search string \p str, which may contain greek/unicode characters like in the SearchDialog.
203Returns a JSON String array of search matches
204
205\paragraph rcObjectServiceInfo info
206Parameters: <tt>[name (String)]</tt>\n
207Returns a HTML info string (StelObject::getInfoString) about the object identified by \p name.
208If no parameter is given, the currently selected object is used.
209
210\paragraph rcObjectServiceListobjecttypes listobjecttypes
211Returns all object types available in the internal catalogs as a JSON array of objects of format
212@code{.js}
213{
214 key, //the internal key for the object type
215 name, //the english name of the type
216 name_i18n //the type name in the current language
217}
218@endcode
219
220\paragraph rcObjectServiceListobjectsbytype listobjectsbytype
221Parameters: <tt>type (String) [english (Number)]</tt>\n
222Returns all objects of the specified \p type. If \p english is given and it evaluates to a "true" value, the english names
223will be returned, otherwise the localized names will be returned. Returns a JSON string array.
224
225\subsection rcScriptService ScriptService operations (/api/scripts/)
226\subsubsection rcScriptServiceGET GET operations
227Implemented by ScriptService::getImpl
228
229\paragraph rcScriptServiceList list
230Lists all known script files, as a JSON string array.
231
232\paragraph rcScriptServiceInfo info
233Parameters: <tt>id (String) [html (any type)] </tt>\n
234Returns information about the script identified by \p id.
235If the optional parameter \p html is present (its value is ignored),
236the info is formatted using StelScriptMgr::getHtmlDescription and
237suitable for inclusion into an \c iframe element,
238otherwise this operation returns a JSON object of format:
239@code{.js}
240{
241 id, //the script ID
242 name, //the english name of the script
243 name_localized, //the localized name of the script
244 description, //the english description of the script
245 description_localized, //the localized description of the script
246 author, //the author(s) of the script
247 license //the license of the script
248}
249@endcode
250
251\paragraph rcScriptServiceStatus status
252Returns the current script status as a JSON object of format:
253@code{.js}
254{
255 scriptIsRunning, //true if a script is running
256 runningScriptId //the currently running script ID
257}
258@endcode
259@note The StelScriptMgr also provides a StelProperty \c StelScriptMgr.runningScriptId that
260can be used to find out the active script.
261
262\subsubsection rcScriptServicePOST POST operations
263Implemented by ScriptService::postImpl
264
265\paragraph rcScriptServiceRun run
266Parameters: <tt>id (String)</tt>\n
267Runs the script with the given \p id. Will fail if a script is currently running.
268
269\paragraph rcScriptServiceDirect direct
270Parameters: <tt>code (String) [useIncludes (Bool)]</tt>\n
271Directly executes the given script \p code. If \p useIncludes is given and evaluates to true, the standard
272include folder will be used. Script execution will fail if a script is already running.
273
274\paragraph rcScriptServiceStop stop
275Stops the execution of a running script.
276
277\subsection rcSimbadService SimbadService operations (/api/simbad/)
278\subsubsection rcSimbadServiceGET GET operations
279Implemented by SimbadService::getImpl
280
281\paragraph rcSimbadServiceLookup lookup
282Parameters: <tt>str (String)</tt>\n
283Performs a SIMBAD lookup for the string \p str using the Stellarium-configured server and returns the results as a JSON object of format
284@code{.js}
285{
286 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
287 status_i18n, //a localized status message for display
288 errorString, //if the status is "error", this contains more information about it
289 results: {
290 names : [
291 //an array of object names
292 ],
293 positions : [
294 //an array of object positions (i.e. first one corresponds to first name, etc.)
295 //format is an array of 3 numbers for each entry, i.e.:
296 [1,2,3],...
297 ]
298 }
299}
300@endcode
301
302\subsection rcStelActionService StelAction operations (/api/stelaction/)
303\subsubsection rcStelActionServiceGET GET operations
304Implemented by StelActionService::getImpl
305
306\paragraph rcStelActionServiceList list
307Lists all registered StelActions, in the format
308@code{.js}
309{
310 //translated StelAction group name
311 <groupName> : [
312 //all StelActions in the group <groupName>
313 <actionName> : {
314 id, //the ID of the action
315 isCheckable, //true if the action represents a boolean value
316 isChecked, //if "isCheckable" is true, shows the current boolean state
317 text //the translated description of the action
318 }
319 ]
320}
321@endcode
322
323\subsubsection rcStelActionServicePOST POST operations
324Implemented by StelActionService::postImpl
325
326\paragraph rcStelActionServiceDo do
327Parameters: <tt>id (String)</tt>\n
328Triggers or toggles the StelAction specified by \p id. If it was a boolean action, returns the new state of the action (strings "true"/"false").
329
330\subsection rcStelPropertyService StelProperty operations (/api/stelproperty/)
331\subsubsection rcStelPropertyServiceGET GET operations
332Implemented by StelPropertyService::getImpl
333
334\paragraph rcStelPropertyServiceList list
335Lists all registered StelProperties, in the format
336@code{.js}
337{
338 <propId> : {
339 value, //the current value of the StelProperty
340 variantType, //the type string of the "value", as determined by QVariant::typeName
341 typeString, //the type string of the StelProperty, as determined by QMetaProperty::typeName (may not be equal to "variantType")
342 typeEnum, //the enum value of the type of the StelProperty, as determined by StelProperty::getType
343 }
344}
345@endcode
346@note The generic type conversions are done by QJsonValue::fromVariant
347
348\subsubsection rcStelPropertyServicePOST POST operations
349Implemented by StelPropertyService::postImpl
350
351\paragraph rcStelPropertyServiceSet set
352Parameters: <tt>id (String) value (String)</tt>\n
353Sets the StelProperty identified by \p id to the value \p value. The value is converted to the StelProperty type
354using QVariant logic, an error is returned if this is somehow not possible.
355
356\subsection rcLocationService LocationService operations (/api/location/)
357\subsubsection rcLocationServiceGET GET operations
358Implemented by LocationService::getImpl
359
360\paragraph rcLocationServiceList list
361Returns the list of all stored location IDs (keys of StelLocationMgr::getAllMap) as JSON string array
362
363\paragraph rcLocationServiceCountrylist countrylist
364Returns the list of all known countries (StelLocaleMgr::getAllCountryNames), as a JSON array of objects of format
365@code
366{
367 name, //the english country name
368 name_i18n //the localized country name (current language)
369}
370@endcode
371
372\paragraph rcLocationServicePlanetlist planetlist
373Returns the list of all solar system planet names (SolarSystem::getAllPlanetEnglishNames), as a JSON array of objects of format
374@code
375{
376 name, //the english planet
377 name_i18n //the localized planet name (current language)
378}
379@endcode
380
381\paragraph rcLocationServicePlanetimage planetimage
382Parameters: <tt>planet (String)</tt>\n
383Returns the planet texture image for the \p planet (english name)
384
385\subsubsection rcLocationServicePOST POST operations
386Implemented by LocationService::postImpl
387
388\paragraph rcLocationServiceSetlocationfields setlocationfields
389Parameters: <tt>id (String) | ( [latitude (Number)] [longitude (Number)] [altitude (Number)] [name (String)] [country (String)] [planet (String)] )</tt>\n
390Changes and moves to a new location.
391If \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.
392Else, the other parameters change the specific field of the current StelLocation.
393
394\subsection rcLocationSearchService LocationSearchService operations (/api/locationsearch/)
395\subsubsection rcLocationSearchServiceGET GET operations
396Implemented by LocationSearchService::getImpl
397
398\paragraph rcLocationSearchServiceSearch search
399Parameters: <tt>term (String)</tt>\n
400Searches the \p term in the list of predefined locations of the StelLocationMgr, and returns a JSON string array of the results.
401
402\paragraph rcLocationSearchServiceNearby nearby
403Parameters: <tt>[planet (String)] [latitude (Number)] [longitude (Number)] [radius (Number)]</tt>\n
404Searches near the location defined by \p planet, \p latitude and \p longitude for predefined locations (inside the given \p radius)
405using StelLocationMgr::pickLocationsNearby, returns a JSON string array.
406
407\subsection rcViewService ViewService operations (/api/view/)
408\subsubsection rcViewServiceGET GET operations
409Implemented by ViewService::getImpl
410
411\paragraph rcViewServiceListlandscape listlandscape
412Lists the installed landscapes as a JSON object of format
413@code{.js}
414{
415 <landscapeId> : <landscapeName>, //maps the landscape id to the translated landscape name
416 ...
417}
418@endcode
419
420\paragraph rcViewServiceLandscapedescription landscapedescription/
421<em>Note that the slash at the end is mandatory!</em>\n
422Provides virtual filesystem access to the current landscape directory.
423The operation can take a longer path in the URL. The remainder is used to access files in the landscape directory.
424If no longer path is given, the current HTML landscape description (as per LandscapeMgr::getCurrentLandscapeHtmlDescription)
425is returned. An example: `landscapedescription/image.png` returns `image.png` from the current landscape directory.
426
427This operation allows to set up an HTML \c iframe or similar for the landscape description, including all images, etc. embedded
428in the HTML description.
429
430\paragraph rcViewServiceListskyculture listskyculture
431Lists the installed sky cultures as a JSON object of format
432@code{.js}
433{
434 <skycultureId> : <skycultureName>, //maps the id to the translated name
435 ...
436}
437@endcode
438
439\paragraph rcViewServiceSkyculturedescription skyculturedescription/
440<em>Note that the slash at the end is mandatory!</em>\n
441Provides virtual filesystem access to the current skyculture directory.
442The operation can take a longer path in the URL. The remainder is used to access files in the skyculture directory.
443If no longer path is given, the current HTML skyculture description (as per StelSkyCultureMgr::getCurrentSkyCultureHtmlDescription)
444is returned. An example: `skyculturedescription/image.png` returns `image.png` from the current skyculture directory.
445
446This operation allows to set up an HTML \c iframe or similar for the skycultures description, including all images, etc. embedded
447in the HTML description.
448
449\paragraph rcViewServiceListprojection listprojection
450Lists the available projection types as a JSON object of format
451@code{.js}
452{
453 <projectionTypeKey> : <projectionName>, //maps the id to the translated name
454 ...
455}
456@endcode
457
458\paragraph rcViewServiceProjectiondescription projectiondescription
459Returns the HTML description of the current projection (StelProjector::getHtmlSummary)
460
461*/
0462
=== added file 'plugins/RemoteControl/doc/remoteControlWeb.doxygen'
--- plugins/RemoteControl/doc/remoteControlWeb.doxygen 1970-01-01 00:00:00 +0000
+++ plugins/RemoteControl/doc/remoteControlWeb.doxygen 2016-06-12 13:59:22 +0000
@@ -0,0 +1,564 @@
1/*
2 * Stellarium
3 * Copyright (C) 2016 Florian Schaukowitsch
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20/*!
21
22\page remoteControlWeb %RemoteControl plugin web interface
23
24\tableofcontents
25
26The \ref remoteControlDoc "RemoteControl plugin", by default, provides a HTML web interface through the same integrated HTTP
27server that serves the \ref remoteControlApi "RemoteControl API". All content found in the <tt>data/webroot</tt> folder is served.
28Note that the \c /api/ path is reserved for the \ref remoteControlApi "HTTP API", and therefore can not be used as a folder.
29The <tt>index.html</tt> file is mapped to the root, so you can access it using http://localhost:8090 with the default port setting
30of 8090. A slightly modified alternative interface (mainly larger buttons for now) for 7" tablets and other touch devices
31is available at http://localhost:8090/tablet7in.html.
32
33A 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>
34and <a href="https://developer.mozilla.org/en/docs/Web/CSS/CSS3">CSS3</a> are used.
35
36The interface heavily relies on <a href="https://jquery.com/">jQuery</a> for easier JavaScript coding. The code is structured into modules,
37and loaded using <a href="http://requirejs.org/">require.js</a>, which automatically resolves dependencies and load order.
38
39\section remoteControlWebStructure File and directory structure
40
41Note that not all files are listed here, only those of special interest.
42
43- webroot/ - root directory
44 - index.html - Default interface, also mapped to the root folder
45 - style.css - Main stylesheet
46 - tablet7in.html - Modified interface for tablet devices
47 - style_tablet7in.css - Additional stylesheet for tablet7in.html
48 - translate_files - Defines which files are passed through StelTranslator, see \ref remoteControlWebTranslation
49 - iframestyle.css - defines the style for internal frames (landscape description, etc.)
50 - /js/ - Contains the JavaScript files required for the interfaces
51 - main.js - This is the configuration file for require.js. Loads \ref rcUiMainui as main module.
52 - settings.js - Contains some configuration options for the web interface
53 - translationdata.js - Auto-generated file containing strings to translate through StelTranslator, see \ref remoteControlWebTranslation
54 - /api/ - Contains .js modules that define the connection to the \ref remoteControlApi "RemoteControl API"
55 - \ref rcApiRemotecontrol
56 - \ref rcApiActions
57 - \ref rcApiFlags
58 - \ref rcApiLocation
59 - \ref rcApiProperties
60 - \ref rcApiScripts
61 - \ref rcApiSearch
62 - \ref rcApiTime
63 - \ref rcApiUpdatequeue
64 - \ref rcApiViewcontrol
65 - \ref rcApiViewoptions
66 - /ui/ - Contains UI-related .js modules which depend on the /api/ .js modules
67 - \ref rcUiMainui
68 - \ref rcUiActions
69 - \ref rcUiCombobox
70 - \ref rcUiJqueryuifixes
71 - \ref rcUiLocation
72 - \ref rcUiScripts
73 - \ref rcUiSearch
74 - \ref rcUiTime
75 - \ref rcUiViewcontrol
76 - \ref rcUiViewoptions
77
78\section remoteControlWebEdit Editing the interface
79
80With knowledge of HTML, CSS and JavaScript (the latter not required for basic modifications), the interface can be customized.
81
82\subsection remoteControlWebBasic Basic extension
83
84When 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),
85but allow you to add functionality to HTML elements without editing the JavaScript code.
86Some of these classes also allow you to add further attributes to the element
87(usually <a href="https://developer.mozilla.org/en/docs/Web/Guide/HTML/Using_data_attributes">HTML5 data attributes</a>)
88to further customize their behaviour.
89
90\subsubsection remoteControlWebUIClasses UI control classes
91
92Some 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
93some modifications.
94
95\paragraph remoteControlWebUIspinner spinner
96If 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/).
97It supports the following optional parameters:
98- \p data-min - Defines the minimum value of the spinner
99- \p data-max - Defines the maximum value of the spinner
100- \p data-step - Defines the desired step size of the spinner, default is 1. May be different from the number format.
101- \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>
102
103The element will emit the custom \c spinuserinput event whenever the value changes (either through the buttons or direct keyboard input).
104An example, showing how a spinner is created and handled:
105\code
106//make a spinner from -50 to 50, always showing 2 decimal points and stepping 0.1 per click
107<input id="myspinner" class="spinner" data-min="-50" data-max="50" data-step="0.1" data-numberformat="n2"/>
108
109//input handling in javascript
110$("#myspinner").on("spinuserinput", function(evt,ui) {
111 //print the new value
112 console.log(ui.value);
113});
114\endcode
115
116\paragraph remoteControlWebUIslider slider
117If 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/).
118It supports the following optional parameters:
119- \p data-min - Defines the minimum value of the slider
120- \p data-max - Defines the maximum value of the slider
121- \p data-step - Defines the desired step size of the slider, default is 1. May be different from the number format.
122
123The element will emit the \c slide event when the slider is moved.
124\code
125//make a slider from -50 to 50, stepsize 0.1
126<div id="myslider" class="slider" data-min="-50" data-max="50" data-step="0.1"/>
127
128//input handling in javascript
129$("#myslider").on("slide", function(evt,ui) {
130 //print the new value
131 console.log(ui.value);
132});
133\endcode
134
135\paragraph remoteControlWebUIjquerybutton jquerybutton
136If added to an HTML \c button element, it converts it to a <a href="https://jqueryui.com/button/">jQuery UI button</a>.
137This is mainly a cosmetic operation.
138
139\paragraph remoteControlWebUIselectmenu selectmenu
140If added to an HTML \c select element, it creates a <a href="https://jqueryui.com/selectmenu/">jQuery UI selectmenu</a> from it.
141This allows simple popup selection menus (like a QComboBox).
142
143\subsubsection remoteControlWebProp Special behaviour classes
144These classes allow automatic connection to StelProperty and StelAction elements defined in Stellarium, allowing particularly easy
145extension of the web interface.
146
147\paragraph remoteControlWebstelproperty stelproperty (Connection to StelProperty)
148Allows direct connection of an element to a StelProperty, meaning the element is automatically updated
149whenever the value in Stellarium changes --- regardless of the source of the change: it can come from the main GUI, scripting, or even
150other RemoteControl web interface instances! Together with the \ref remoteControlWebUIClasses listed above, this allows closely and easily recreating
151standard Stellarium interface elements. This is supported for:
152- \c input elements with the \c spinner class (for numerical properties)\n
153 The StelProperty to use is identified by the standard \c input attribute \p name.
154 Updates the \p value property of the \c input when the StelProperty changes, and reacts to \c spinuserinput events to update the property
155
156- \c input elements of type \c checkbox (`<input type="checkbox">` (for boolean properties)\n
157 The StelProperty to use is identified by the standard \c input attribute \p name.
158 Uses the \p checked property and the \c click event.
159
160- \c div elements with the \c slider class (for numerical properties)\n
161 The StelProperty to use is identified by the custom attribute \p data-prop.
162 Connects to the \c slider widget property \p value.
163
164- \c select elements (also supports the optional \c selectmenu classs)\n
165 The StelProperty to use is identified by the standard \c select attribute \p name.
166 Sets the \c option that has the same \p value as the StelProperty value.
167 Useful for single selection out of a list of possibilities.
168
169- \c span elements, for read-only property display with optional number format\n
170 The StelProperty to use is identified by the custom attribute \p data-prop.
171 The value is displayed using the element's text content.
172 The optional \p data-numberformat attribute is used for the number format
173 using [globalize.js 0.1.1 syntax](https://github.com/jquery/globalize/blob/v0.1.1/README.md#numbers)
174
175- \c button or `input[type="button"]` elements, for write-only setting of a StelProperty to a pre-defined value when clicked\n
176 The StelProperty to use is identified by the standard attribute \p name,
177 and the value to set it to is defined by the attribute \p value.
178
179An example, setting up a spinner for the \c MilkyWay.intensity StelProperty:
180\code{.html}
181<!-- this is all that is required, the rest is done automatically -->
182<input class="spinner stelproperty" name="MilkyWay.intensity" data-min="0" data-max="10" data-step="0.1" data-numberformat="n2"/>
183\endcode
184
185Many more examples can be found by studying the `index.html` code.
186
187\paragraph remoteControlWebstelaction stelaction (Connection to StelAction)
188When this class is added to \c button elements or \c input elements of `type="button"` or `type="checkbox"`,
189this connects the control to a StelAction. The action is identified by the \p name attribute.
190If the action is a boolean action (i.e. StelAction::isCheckable is true), checkboxes show the current state of the action,
191and buttons get the \c active CSS class assigned if the action is currently true.
192
193Examples:
194\code{.html}
195<!-- This is how the main bottom button bar is defined -->
196<ul class="ui-corner-all ui-widget-content button32list margin-vertical">
197 <li><button class="stelaction icon32 btConstellationLines" name="actionShow_Constellation_Lines"></button></li>
198 <li><button class="stelaction icon32 btConstellationLabels" name="actionShow_Constellation_Labels"></button></li>
199 <li><button class="stelaction icon32 btConstellationArt" name="actionShow_Constellation_Art"></button></li>
200 <li><button class="stelaction icon32 btEquatorialGrid" name="actionShow_Equatorial_Grid"></button></li>
201 <li><button class="stelaction icon32 btAzimuthalGrid" name="actionShow_Azimuthal_Grid"></button></li>
202 <li><button class="stelaction icon32 btGround" name="actionShow_Ground"></button></li>
203 <li><button class="stelaction icon32 btCardinalPoints" name="actionShow_Cardinal_Points"></button></li>
204 <li><button class="stelaction icon32 btAtmosphere" name="actionShow_Atmosphere"></button></li>
205 <li><button class="stelaction icon32 btNebula" name="actionShow_Nebulas"></button></li>
206 <li><button class="stelaction icon32 btPlanets" name="actionShow_Planets_Labels"></button></li>
207 <li><button class="stelaction icon32 btEquatorialMount" name="actionSwitch_Equatorial_Mount"></button></li>
208 <li><button class="stelaction icon32 btGotoSelectedObject" name="actionSet_Tracking"></button></li>
209 <li><button class="stelaction icon32 btNightView" name="actionShow_Night_Mode"></button></li>
210 <li><button class="stelaction icon32 btFullScreen" name="actionSet_Full_Screen_Global"></button></li>
211</ul>
212
213<!-- This is how to set up checkboxes -->
214<label><input type="checkbox" class="stelaction" name="actionShow_Planets" /><?= tr("Show Solar System objects")?></label>
215<label><input type="checkbox" class="stelaction" name="actionShow_Planets_Hints" /><?= tr("Show planet markers")?></label>
216<label><input type="checkbox" class="stelaction" name="actionShow_Planets_Orbits" /><?= tr("Show planet orbits")?></label>
217\endcode
218
219\paragraph remoteControlWebStelssc stelssc (Direct script execution)
220This class allows you to define buttons that directly execute Stellarium \ref scripting code.
221Supported for \c button and \c input elements of type \p button. The code to execute should be stored inside
222the element's \p value property. If the custom attribute \p data-useincludes attribute is added (with any value),
223the default include folder is added for optional includes, but this is not recommended unless necessary.
224
225An example:
226\code{.html}
227<!-- some buttons which move the view to predefined angles -->
228<button type="button" class="stelssc" value="core.moveToAltAzi(0., 0., 3.)">0&deg;</button>
229<button type="button" class="stelssc" value="core.moveToAltAzi(0., 30., 3.)">30&deg;</button>
230<button type="button" class="stelssc" value="core.moveToAltAzi(0., 60., 3.)">60&deg;</button>
231<button type="button" class="stelssc" value="core.moveToAltAzi(0., 90., 3.)">90&deg;</button>
232<button type="button" class="stelssc" value="core.moveToAltAzi(0., 120., 3.)">120&deg;</button>
233<button type="button" class="stelssc" value="core.moveToAltAzi(0., 150., 3.)">150&deg;</button>
234<button type="button" class="stelssc" value="core.moveToAltAzi(0., 180., 3.)">180&deg;</button>
235<button type="button" class="stelssc" value="core.moveToAltAzi(0., 210., 3.)">210&deg;</button>
236<button type="button" class="stelssc" value="core.moveToAltAzi(0., 240., 3.)">240&deg;</button>
237<button type="button" class="stelssc" value="core.moveToAltAzi(0., 270., 3.)">270&deg;</button>
238<button type="button" class="stelssc" value="core.moveToAltAzi(0., 300., 3.)">300&deg;</button>
239<button type="button" class="stelssc" value="core.moveToAltAzi(0., 330., 3.)">330&deg;</button>
240\endcode
241
242\warning
243The \c stelssc approach has some disadvantages, so try to use it only when necessary:
244- causes a larger overhead for Stellarium internally than other methods provided by the web interface
245- the scripts can't be executed if another script is currently running, an error message will be shown in this case
246 - this also includes the user clicking too fast on any \c stelssc buttons!
247
248\paragraph remoteControlWebStelplugin stelplugin (Plugin-specific sections)
249With the CSS class \c stelplugin, one can create special HTML sections that
250are only shown when a specified [plugin](\ref plugins) is currently loaded by Stellarium.
251If the plugin is not loaded, the whole element and all it's children are removed from the DOM.
252This class can be added to any element. The plugin which is required is defined by the
253\c data-plugin attribute, which should be set to the plugin ID.
254
255The optional \c data-pluginjs attribute can be used to define an additional JavaScript module that is only
256loaded when the plugin is loaded. This can be used to implement additional behaviour through JS, if required.
257It is recommended to put these modules into the `webroot/js/plugins` folder.
258
259An example, defining the plugin panel for the \ref archaeoLines :
260\code
261<div id="vo_archaeolines" class="smallblock stelplugin" data-plugin="ArchaeoLines" data-pluginjs="plugins/archaeolines">
262 <h3><label><input type="checkbox" class="stelaction valign-middle" name="actionShow_Archaeo_Lines"/><?= tr("ArchaeoLines")?></label></h3>
263 <div class="inline-block blocklabel">
264 <label><input type="checkbox" class="stelaction" name="actionAL_showEquinoxLine"/><?= tr("Equinox")?></label>
265 <label><input type="checkbox" class="stelaction" name="actionAL_showSolsticeLines"/><?= tr("Solstices")?></label>
266 <label><input type="checkbox" class="stelaction" name="actionAL_showCrossquarterLines"/><?= tr("Crossquarters")?></label>
267 <label><input type="checkbox" class="stelaction" name="actionAL_showMajorStandstillLines"/><?= tr("Major Standstill")?></label>
268 <label><input type="checkbox" class="stelaction" name="actionAL_showMinorStandstillLines"/><?= tr("Minor Standstill")?></label>
269 </div>
270 <div class="inline-block blocklabel">
271 <label><input type="checkbox" class="stelaction" name="actionAL_showZenithPassageLine"/><?= tr("Zenith Passage")?></label>
272 <label><input type="checkbox" class="stelaction" name="actionAL_showNadirPassageLine"/><?= tr("Nadir Passage")?></label>
273 <label><input type="checkbox" class="stelaction" name="actionAL_showSelectedObjectLine"/><?= tr("Selected Object")?></label>
274 <label><input type="checkbox" class="stelaction" name="actionAL_showCurrentSunLine"/><?= tr("Current Sun")?></label>
275 <label><input type="checkbox" class="stelaction" name="actionAL_showCurrentMoonLine"/><?= tr("Current Moon")?></label>
276 </div>
277 <label class="display-block" for="select_ArchaeoLines_enumShowCurrentPlanet"><?= tr("Current Planet:")?></label>
278 <select id="select_ArchaeoLines_enumShowCurrentPlanet" class="selectmenu stelproperty display-block" name="ArchaeoLines.enumShowCurrentPlanet">
279 <option value="10"><?= tr("None")?></option>
280 <option value="11"><?= tr("Mercury")?></option>
281 <option value="12"><?= tr("Venus")?></option>
282 <option value="13"><?= tr("Mars")?></option>
283 <option value="14"><?= tr("Jupiter")?></option>
284 <option value="15"><?= tr("Saturn")?></option>
285 </select>
286</div>
287
288//the contents of plugins/archaeolines.js
289define(["jquery"],function($){
290 "use strict";
291
292 //this is just an example how to use additional dynamically loaded plugin files
293 console.log("Hello, this is a asynchronously loaded plugin javascript file!");
294
295});
296\endcode
297
298\subsection remoteControlWebTranslation Translation information
299
300The interface can be translated using methods similar to the main program.
301All strings in the HTML markup that should be translated can be written
302between pseudo-PHP style tags and the \c tr function to achieve the same effect as the `q_()` macro in C++, like so:
303\code
304<label><input type="checkbox" class="stelaction" name="actionShow_Planets" /><?= tr("Show Solar System objects")?></label>
305\endcode
306
307All files which are listed in the `webroot/translate_files` file will be parsed, and all `<?= tr("----")?>` tags will be
308replaced using the StelTranslator for the current application language.
309
310If you require translated strings through JavaScript, you should use the `tr` method of the \ref rcApiRemotecontrol module,
311which also works similar to the `q_()` macro. There is a special procedure for the JavaScript strings: the target
312\c RemoteControl-update-translationdata should be run whenever new JavaScript strings have been added.
313This updates the file `webroot/js/translationdata.js` with all current `tr()` strings. [Python](https://www.python.org/)
314is required to be installed for this operation.
315
316Like the main program, the strings can be extracted from the HTML/JS code using gettext/xgettext. There are CMake targets for this like
317for the C++ code (\c generate-pot-stellarium-remotecontrol, \c update-po-stellarium-remotecontrol, etc.) and they are also executed
318with the combined targets (\c generate-pot, \c update-po etc.).
319
320\subsection remoteControlJS JavaScript module reference
321
322All interface code is developed using [require.js modules](http://requirejs.org/docs/api.html#define).
323This allows defining the dependencies of each module, as well as easier maintainability.
324Each module should be defined in its own .js file. The module ID corresponds to the .js file name
325without the file extension.
326
327In short, to define a module, wrap it in a \c define call, and optionally add dependencies.
328A basic example (for more ways to do it see the require.js doc):
329\code
330//myawesomemodule.js
331//the IDs of the dependencies are listed in an array as first parameter
332//the second parameter is usually a function which takes the actual instances of the dependencies as a parameter,
333// in the same order as they are in the array!
334define(["jquery", "api/remotecontrol"], function($,rc) {
335 "use strict"; //it is recommended to use strict mode for each module
336
337 //do something as soon as this module is loaded
338 console.log("my awesome module is being loaded!");
339
340 //do something when the DOM is ready (because that is not guaranteed while the module is first bein loaded!)
341 $(function(){
342 console.log("the document is ready, you can access the elements now!");
343 //access an element and modifiy it
344 $("#myelement").text("hey, this is awesome");
345 });
346
347 //react to the serverDataReceived event of the remotecontrol module
348 $(rc).on("serverDataReceived", function(evt,data) {
349 console.log("Stellarium just sent us new data!");
350 console.log("The current jDay is " + data.time);
351 });
352
353 //provide some public methods that other modules may call
354 return {
355 myAwesomeMethod: function() {
356 console.log("Hello there!");
357 }
358 };
359});
360
361//another module (in another file) can now reference our module as dependency to load it and use its methods
362define(["jquery", "myawesomemodule"],function($, awesome) {
363
364 awesome.myAwesomeMethod(); //prints "Hello there!"
365});
366\endcode
367
368The UI modules can depend on the API modules and other UI modules.
369The API modules can depend on other API modules.
370Circular dependencies should of course be avoided.
371
372\subsubsection rcApiRemotecontrol api/remotecontrol
373
374This is the main API module, with no further dependencies on other API modules.
375
376Its main function is that it provides automatic status updates by periodically polling (by default each second) the
377\c status operation of the MainService. Whenever this poll succeeds, the \c serverDataReceived custom event is emitted,
378with the JSON response of the server as \p data parameter. Other API modules should use this event, and process
379the data in which they are interested.
380It also keeps track of StelAction and StelProperty changes,
381and emits \c stelActionsChanged and/or \c stelPropertiesChanged, if necessary. Note that it does not process them further,
382this is the job of the \ref rcApiActions and \ref rcApiProperties modules, respectively.
383When the connection to the server is lost (i.e. the polling returned an error), the \c serverDataError event is sent.
384
385The other main function is that it provides the \c postCmd method, which is a simple wrapper around an AJAX POST call
386that is intended to be used by other modules to send commands to the server. It also includes the \c tr method used
387for [translating JS strings](\ref remoteControlWebTranslation).
388
389Finally, this module also processes the [plugin-specific sections](\ref remoteControlWebStelplugin) on load.
390
391\subsubsection rcApiActions api/actions
392
393Processes StelAction related events. Whenever it detects that boolean StelAction was changed, it emits two events:
394- A generic event \c stelActionChanged with the \c actionId as a parameter. This can be used when interested in ALL action changes
395 (like for a action list)
396- A specialied event `stelActionChanged:<actionId>` with the \c actionId as part of the event name.
397 This can be used when listening for a specific action only.
398
399On the first load of the interface, it loads a list of all actions (using the ActionService \c list operation) and emits the
400\c actionListLoaded event when this data is available.
401
402To execute/toggle an action, it provides the public \c executeAction method, which just requires the action ID as parameter.
403To find out whether an action is currently checked, use the \c isChecked method.
404
405\subsubsection rcApiFlags api/flags
406
407This is a utility module, which can be used to implement checkboxes for enum flag types, where each checkbox sets a
408specific bit of a single value. The module should be constructed with \c new, the constructor takes the parent element of a list of
409checkboxes (\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
410\c setValue method to set the current value and check the correct checkboxes. The bit value of each \c input should be specified
411as its \p value property, in hexadecimal string format (for example `0x0004`)
412
413\subsubsection rcApiLocation api/location
414
415Module which connects to the LocationService and the LocationSearchService.
416It emits the following events whenever the specified field changed:
417\c planetChanged,\c nameChanged, \c countryChanged, \c altitudeChanged, \c latitudeChanged, \c longitudeChanged, \c positionChanged (emitted when either lat or lon changed)
418
419It also has \c set methods for these fields.
420Furthermore, it provides \c performLocationSearch, which searches the predefined locations for a specific search string,
421and \c performNearbySearch, which searches predefined locations near a given lat/lon on the current planet.
422These methods take a callback parameter to notify the caller of the results.
423The \c setLocationById method can then be used to set the location to a result of these 2 methods.
424
425It also provides a \c loadCountryList and a \c loadPlanetList which load the specified lists and return the results with a callback.
426
427\subsubsection rcApiProperties api/properties
428
429Processes StelProperty related things. Like the \ref rcApiActions module, it emits 2 events when it detects a StelProperty changed:
430- A generic event \c stelPropertyChanged with the \c propertyId as a parameter. This can be used when interested in ALL property changes
431 (like for a list)
432- A specialied event `stelPropertyChanged:<propertyId>` with the \c propertyId as part of the event name.
433 This can be used when listening for a specific property only.
434
435It provides \c getStelProp and \c setStelProp methods which retrieve and set the value of a StelProperty,
436and also a \c setStelPropQueued convenience method to batch multiple fast interface changes (e.g. through a slider or spinner)
437into a single \c setStelProp call which is only executed after a small time has passed with no changes.
438
439It also emits the \c propertyListLoaded event when it first loads the full list of StelProperties with their type information.
440
441\subsubsection rcApiScripts api/scripts
442
443This module handles script execution (i.e. connection to the ScriptService). It provides the following methods:
444- \c loadScriptList - loads the list of all scripts, takes a callback to return this data
445- \c runScript - runs the specified script id
446- \c runDirectScript - directly runs the given script code
447- \c stopScript - stops a currently running script
448
449It also emits the \c activeScriptChanged event whenever it detects that the current script has changed or started/stopped
450
451\subsubsection rcApiSearch api/search
452
453Implements object search functionality, connecting to the ObjectService and the SimbadService. The following methods are provided:
454- \c loadObjectTypes - loads the list of object types, takes a callback
455- \c loadObjectList - loads the list of objects of a specified type, can return english or localized names
456- \c selectObjectByName - selects the object that matches the specified name
457- \c focusPosition - focuses the given coordinate (array of 3 numbers) in the J2000 frame
458- \c performSearch - performs an object lookup in Stellarium's internal catalog and Simbad. In addition to the search string,
459 2 callbacks must be given as parameters: one for the catalog results, and one for the simbad results. If a search is currently running,
460 it is aborted (meaning the callbacks won't be called for the old searches), allowing this method to be repeatedly called while
461 the user is typing. The Simbad search is only started after a small interval without typing, to reduce the overhead of the
462 external web requests.
463
464While a search is running, it emits \c simbadStateChange events to notify the UI of the current state of the lookup.
465
466\subsubsection rcApiTime api/time
467
468Contains time-related functions and conversions, similar to what StelCore does. This module keeps it's own sense of Stellariums current time,
469to provide an updated interface even between the \c status polls of the \ref rcApiRemotecontrol module.
470
471It provides following methods:
472- \c getCurrentTime - calculates the best guess to the current Stellarium simulation time. This depends on the information received with the last \c status poll,
473 the time since the last data was received and the time the last time change was performed
474- \c isRealTimeSpeed - true if the simulation time currently flows at the same rate as the real time (1 sec per sec).
475- \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
476 of a JS Date object because of its limitations.
477- \c jdayToDate - returns the time component of the given jDay, as a JS object with \p hour, \p minute, \p second fields
478- \c dateTimeToJd - converts a time given in Y/M/D-H/MIN/S format to a jDay
479- \c dateTimeForRollover - like StelUtils::changeDateTimeForRollover
480- \c isTimeUpdatePending - if true, there is a time change which has not yet been sent to the server
481- \c increaseTimeRate - increases the Stellarium simulation time rate (like StelCore::increaseTimeSpeed)
482- \c decreaseTimeRate - decreases the Stellarium simulation time rate (like StelCore::decreaseTimeSpeed)
483- \c isRewind - returns true if the time currently flows backwards (at least at -0.99 sec / sec)
484- \c isFastForward - returns true if time currently is flowing faster than real time
485- \c isTimeNow - returns true if the current simulation time is very close to the actual system time
486- \c isTimeStopped - returns true if the simulation time rate is zero
487- \c togglePlayPause - toggles between timerates 0 and 1 sec/sec
488- \c setDateNow - sets the simulation time to the current system time
489- \c setJDay - sets the time to the specified JDay
490- \c setTimeFromTimeObj - sets the time from a "time object", containing both date and time in the following format
491\code
492{
493 date : {
494 year, month, day
495 },
496 time : {
497 hour, minute, second
498 }
499}
500\endcode
501- \c getTimeData - returns the current time data, containing the last response from the server (including timezone info, etc)
502 The event \c timeDataUpdated is sent whenever this changes.
503
504\subsubsection rcApiUpdatequeue api/updatequeue
505
506This implements a simple update queue class that updates the server after a specified interval if the user does nothing else inbetween.
507This 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,
508and when the interface needs to send an update, \c enqueue can be called with the data to send.
509
510\subsubsection rcApiViewcontrol api/viewcontrol
511
512Implements the %FOV access and viewport movement methods. Use \c setFOV to set the %FOV, the \c fovChanged event is sent whenever the %FOV changes.
513There are \c moveRight, \c moveUp, \c moveUpRight etc. methods that allow the user to move the viewport. To stop the movement, use \c stopMovement.
514
515\subsubsection rcApiViewoptions api/viewoptions
516
517Implements the loading of the projection, landscape and skyculture lists.
518
519\subsubsection rcUiMainui ui/mainui
520
521This is the main module of the interface. It lists all the other UI modules as a dependency.
522It starts of the update look of the \c rcApiRemotecontrol module, handles the automatic generation
523of the [special controls](\ref remoteControlWebUIClasses) and [connection of StelProperty controls](\ref remoteControlWebstelproperty),
524and performs smooth animation of the time controls. It also keeps track of the current interface tab the user is on, and
525restores it when the page is reloaded.
526
527\subsubsection rcUiActions ui/actions
528
529Implements the action list and the [StelAction buttons and checkboxes](\ref remoteControlWebstelaction).
530
531\subsubsection rcUiCombobox ui/combobox
532
533Implements a custom combobox control, on top of the jQuery UI \c autocomplete control. This is used for example in the location controls.
534
535\subsubsection rcUiJqueryuifixes ui/jqueryuifixes
536
537Includes some fixes to the standard jQuery UI control classes, especially for the spinner, to provide a unified
538change event, prevent non-numeric input and better touch support. This module is automatically loaded whenever other modules
539load the "jquery-ui" module.
540
541\subsubsection rcUiLocation ui/location
542
543Implements the location controls, such as the map which can be clicked and the comboboxes for the current location.
544
545\subsubsection rcUiScripts ui/scripts
546
547Implements the script list and shows the active script.
548
549\subsubsection rcUiSearch ui/search
550
551Implements the object search panel and the quick select buttons.
552
553\subsubsection rcUiTime ui/time
554
555Implements the time controls, the \c updateTimeDisplay method is called repeatedly as an animation by the \ref rcUiMainui module.
556
557\subsubsection rcUiViewcontrol ui/viewcontrol
558
559Implements the %FOV slider and the "virtual joystick" for the viewport movement.
560
561\subsubsection rcUiViewoptions ui/viewoptions
562
563Implements the projection, landscape and skyculture lists, and some minor things related to other view options.
564*/
0565
=== added directory 'plugins/RemoteControl/resources'
=== added file 'plugins/RemoteControl/resources/bt_network_templates.tif'
1Binary files plugins/RemoteControl/resources/bt_network_templates.tif 1970-01-01 00:00:00 +0000 and plugins/RemoteControl/resources/bt_network_templates.tif 2016-06-12 13:59:22 +0000 differ566Binary files plugins/RemoteControl/resources/bt_network_templates.tif 1970-01-01 00:00:00 +0000 and plugins/RemoteControl/resources/bt_network_templates.tif 2016-06-12 13:59:22 +0000 differ
=== added file 'plugins/RemoteControl/resources/bt_remote_off.png'
2Binary files plugins/RemoteControl/resources/bt_remote_off.png 1970-01-01 00:00:00 +0000 and plugins/RemoteControl/resources/bt_remote_off.png 2016-06-12 13:59:22 +0000 differ567Binary files plugins/RemoteControl/resources/bt_remote_off.png 1970-01-01 00:00:00 +0000 and plugins/RemoteControl/resources/bt_remote_off.png 2016-06-12 13:59:22 +0000 differ
=== added file 'plugins/RemoteControl/resources/bt_remote_on.png'
3Binary files plugins/RemoteControl/resources/bt_remote_on.png 1970-01-01 00:00:00 +0000 and plugins/RemoteControl/resources/bt_remote_on.png 2016-06-12 13:59:22 +0000 differ568Binary files plugins/RemoteControl/resources/bt_remote_on.png 1970-01-01 00:00:00 +0000 and plugins/RemoteControl/resources/bt_remote_on.png 2016-06-12 13:59:22 +0000 differ
=== added directory 'plugins/RemoteControl/src'
=== added file 'plugins/RemoteControl/src/APIController.cpp'
--- plugins/RemoteControl/src/APIController.cpp 1970-01-01 00:00:00 +0000
+++ plugins/RemoteControl/src/APIController.cpp 2016-06-12 13:59:22 +0000
@@ -0,0 +1,141 @@
1/*
2 * Stellarium Remote Control plugin
3 * Copyright (C) 2015 Florian Schaukowitsch
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 */
19
20#include "APIController.hpp"
21#include <QJsonDocument>
22
23
24APIController::APIController(int prefixLength, QObject* parent) : HttpRequestHandler(parent), m_prefixLength(prefixLength)
25{
26
27}
28
29APIController::~APIController()
30{
31
32}
33
34void APIController::update(double deltaTime)
35{
36 mutex.lock();
37 foreach(AbstractAPIService* service, m_serviceMap)
38 {
39 service->update(deltaTime);
40 }
41 mutex.unlock();
42}
43
44void APIController::registerService(AbstractAPIService *service)
45{
46 m_serviceMap.insert(service->serviceName(), service);
47}
48
49void APIController::service(HttpRequest &request, HttpResponse &response)
50{
51 //disable caching by default for services
52 response.setHeader("Cache-Control","no-cache");
53 //default content type is text
54 response.setHeader("Content-Type","text/plain");
55
56 //use the raw path here
57 QByteArray path = request.getRawPath();
58 QByteArray pathWithoutPrefix = path.right(path.size()-m_prefixLength);
59
60 int slashIdx = pathWithoutPrefix.indexOf('/');
61
62 QByteArray serviceString = pathWithoutPrefix;
63 QByteArray operation;
64 if(slashIdx>=0)
65 {
66 serviceString = pathWithoutPrefix.mid(0,slashIdx);
67 operation = pathWithoutPrefix.mid(slashIdx+1);
68 }
69
70 //try to find service
71 //the mutex here is to prevent a very strange crash I had, in which sv is an invalid pointer (but m_serviceMap is ok)
72 //probably caused by the foreach loop in update in the main thread?
73 mutex.lock();
74 ServiceMap::iterator it = m_serviceMap.find(serviceString);
75 if(it!=m_serviceMap.end())
76 {
77 AbstractAPIService* sv = *it;
78 mutex.unlock();
79
80 //create the response object
81 APIServiceResponse apiresponse;
82 if(request.getMethod()=="GET")
83 {
84#ifdef FORCE_THREADED_SERVICES
85 apiresponse = sv->get(operation, request.getParameterMap());
86#else
87 if(sv->supportsThreadedOperation())
88 {
89 apiresponse = sv->get(operation, request.getParameterMap());
90 }
91 else
92 {
93 //invoke it in the main thread!
94 QMetaObject::invokeMethod(sv,"get",Qt::BlockingQueuedConnection,
95 Q_RETURN_ARG(APIServiceResponse, apiresponse),
96 Q_ARG(QByteArray, operation),
97 Q_ARG(APIParameters, request.getParameterMap()));
98 }
99#endif
100 apiresponse.applyResponse(&response);
101 }
102 else if (request.getMethod()=="POST")
103 {
104#ifdef FORCE_THREADED_SERVICES
105 apiresponse = sv->post(operation, request.getParameterMap(), request.getBody());
106#else
107 if(sv->supportsThreadedOperation())
108 {
109 apiresponse = sv->post(operation, request.getParameterMap(), request.getBody());
110 }
111 else
112 {
113 QMetaObject::invokeMethod(sv,"post",Qt::BlockingQueuedConnection,
114 Q_RETURN_ARG(APIServiceResponse, apiresponse),
115 Q_ARG(QByteArray, operation),
116 Q_ARG(APIParameters, request.getParameterMap()),
117 Q_ARG(QByteArray, request.getBody()));
118 }
119#endif
120 apiresponse.applyResponse(&response);
121 }
122 else
123 {
124 response.setStatus(405,"Method Not allowed");
125 QString str(QStringLiteral("Method %1 not allowed for service %2"));
126 response.write(str.arg(QString::fromLatin1(request.getMethod())).arg(QString::fromUtf8(pathWithoutPrefix)).toUtf8(),true);
127 }
128 }
129 else
130 {
131 mutex.unlock();
132 response.setStatus(400,"Bad Request");
133 QString str(QStringLiteral("Unknown service: '%1'\n\nAvailable services:\n").arg(QString::fromUtf8(pathWithoutPrefix)));
134 for(ServiceMap::iterator it = m_serviceMap.begin();it!=m_serviceMap.end();++it)
135 {
136 str.append(QString::fromUtf8(it.key()));
137 str.append("\n");
138 }
139 response.write(str.toUtf8(),true);
140 }
141}
0142
=== added file 'plugins/RemoteControl/src/APIController.hpp'
--- plugins/RemoteControl/src/APIController.hpp 1970-01-01 00:00:00 +0000
+++ plugins/RemoteControl/src/APIController.hpp 2016-06-12 13:59:22 +0000
@@ -0,0 +1,64 @@
1/*
2 * Stellarium Remote Control plugin
3 * Copyright (C) 2015 Florian Schaukowitsch
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 */
19
20#ifndef APIHANDLER_HPP_
21#define APIHANDLER_HPP_
22
23#include "httpserver/httprequesthandler.h"
24#include "AbstractAPIService.hpp"
25
26#include <QMutex>
27
28//! @ingroup remoteControl
29//! This class handles the API-specific requests and dispatches them to the correct AbstractAPISerice implementation.
30//! Services are registered using registerService().
31//! To see the default services used, see the RequestHandler::RequestHandler constructor.
32class APIController : public HttpRequestHandler
33{
34 Q_OBJECT
35public:
36 //! Constructs an APIController
37 //! @param prefixLength Determines how many characters to strip from the front of the request path
38 //! @param parent passed on to QObject constructor
39 APIController(int prefixLength, QObject* parent = 0);
40 virtual ~APIController();
41
42 //! Should be called each frame from the main thread, like from StelModule::update.
43 //! Passed on to each AbstractAPIService::update method for optional processing.
44 void update(double deltaTime);
45
46 //! Handles an API-specific request. It finds out which AbstractAPIService to use
47 //! depending on the service name (first part of path until slash). An error is returned for invalid requests.
48 //! If a service was found, the request is passed on to its AbstractAPIService::get or AbstractAPIService::post
49 //! method depending on the HTTP request type.
50 //! If AbstractAPIService::supportsThreadedOperation is false, these methods are called in the Stellarium main thread
51 //! using QMetaObject::invokeMethod, otherwise they are directly executed in the current thread (HTTP worker thread).
52 virtual void service(HttpRequest& request, HttpResponse& response);
53
54 //! Registers a service with the APIController.
55 //! The AbstractAPIService::serviceName() determines the request path of the service.
56 void registerService(AbstractAPIService* service);
57private:
58 int m_prefixLength;
59 typedef QMap<QByteArray,AbstractAPIService*> ServiceMap;
60 ServiceMap m_serviceMap;
61 QMutex mutex;
62};
63
64#endif
065
=== added file 'plugins/RemoteControl/src/AbstractAPIService.cpp'
--- plugins/RemoteControl/src/AbstractAPIService.cpp 1970-01-01 00:00:00 +0000
+++ plugins/RemoteControl/src/AbstractAPIService.cpp 2016-06-12 13:59:22 +0000
@@ -0,0 +1,159 @@
1/*
2 * Stellarium Remote Control plugin
3 * Copyright (C) 2015 Florian Schaukowitsch
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 */
19
20#include "AbstractAPIService.hpp"
21#include <QJsonDocument>
22
23#include "httpserver/httpresponse.h"
24
25int APIServiceResponse::metaTypeId = qRegisterMetaType<APIServiceResponse>();
26int APIServiceResponse::parametersMetaTypeId = qRegisterMetaType<APIParameters>();
27
28void APIServiceResponse::setHeader(const QByteArray &name, const QByteArray &val)
29{
30 headers.insert(name,val);
31}
32
33void APIServiceResponse::setHeader(const QByteArray &name, const int val)
34{
35 headers.insert(name,QByteArray::number(val));
36}
37
38void APIServiceResponse::setStatus(int status, const QByteArray &text)
39{
40 this->status = status;
41 this->statusText = text;
42}
43
44void APIServiceResponse::applyResponse(HttpResponse *response) const
45{
46 if(status != -1)
47 {
48 response->setStatus(status,statusText);
49 }
50
51 //apply headers
52 response->getHeaders().unite(headers);
53
54 //send response data, if any
55 if(responseData.isEmpty())
56 {
57 response->getHeaders().clear();
58 response->setStatus(500,"Internal Server Error");
59 response->write("Service provided no response",true);
60 }
61 response->write(responseData,true);
62}
63
64void APIServiceResponse::setData(const QByteArray &data)
65{
66 this->responseData = data;
67}
68
69void APIServiceResponse::appendData(const QByteArray &data)
70{
71 this->responseData.append(data);
72}
73
74void APIServiceResponse::writeRequestError(const QByteArray &msg)
75{
76 setStatus(400,"Bad Request");
77 responseData = msg;
78}
79
80void APIServiceResponse::writeJSON(const QJsonDocument &doc)
81{
82#ifdef QT_NO_DEBUG
83 //Use compact JSON format for release builds for smaller files
84 QByteArray data = doc.toJson(QJsonDocument::Compact);
85#else
86 //Use indented JSON format in debug builds for easier human reading
87 QByteArray data = doc.toJson(QJsonDocument::Indented);
88#endif
89 //setHeader("Content-Length",data.size());
90 setHeader("Content-Type","application/json; charset=utf-8");
91 setData(data);
92}
93
94
95void AbstractAPIService::update(double deltaTime)
96{
97 Q_UNUSED(deltaTime);
98}
99
100bool AbstractAPIService::supportsThreadedOperation() const
101{
102 return false;
103}
104
105APIServiceResponse AbstractAPIService::get(const QByteArray &operation, const APIParameters &parameters)
106{
107 APIServiceResponse response;
108 getImpl(operation,parameters,response);
109 return response;
110}
111
112APIServiceResponse AbstractAPIService::post(const QByteArray &operation, const APIParameters &parameters, const QByteArray &data)
113{
114 APIServiceResponse response;
115 postImpl(operation,parameters,data,response);
116 return response;
117}
118
119#ifdef FORCE_THREADED_SERVICES
120const Qt::ConnectionType AbstractAPIService::SERVICE_DEFAULT_INVOKETYPE = Qt::BlockingQueuedConnection;
121#else
122const Qt::ConnectionType AbstractAPIService::SERVICE_DEFAULT_INVOKETYPE = Qt::DirectConnection;
123#endif
124
125void AbstractAPIService::getImpl(const QByteArray& operation, const QMultiMap<QByteArray, QByteArray> &parameters, APIServiceResponse &response)
126{
127 Q_UNUSED(operation);
128 Q_UNUSED(parameters);
129
130 response.setStatus(405,"Method Not allowed");
131 QString str(QStringLiteral("Method GET not allowed for service %2"));
132
133 response.setData(str.arg(QString::fromLatin1(serviceName())).toLatin1());
134}
135
136void AbstractAPIService::postImpl(const QByteArray& operation, const QMultiMap<QByteArray, QByteArray> &parameters, const QByteArray &data, APIServiceResponse &response)
137{
138 Q_UNUSED(operation);
139 Q_UNUSED(parameters);
140 Q_UNUSED(data);
141
142 response.setStatus(405,"Method Not allowed");
143 QString str(QStringLiteral("Method POST not allowed for service %2"));
144 response.setData(str.arg(QString::fromLatin1(serviceName())).toLatin1());
145}
146
147
148QString AbstractAPIService::wrapHtml(QString &text, const QString &title) const
149{
150 const QString head = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n"
151 "<html><head>\n"
152 "<title>" + title + "</title>\n"
153 "<link type=\"text/css\" rel=\"stylesheet\" href=\"/iframestyle.css\">\n"
154 "<base target=\"_blank\">\n"
155 "</head><body>\n";
156 const QString tail = "</body></html>";
157
158 return text.prepend(head).append(tail);
159}
0160
=== added file 'plugins/RemoteControl/src/AbstractAPIService.hpp'
--- plugins/RemoteControl/src/AbstractAPIService.hpp 1970-01-01 00:00:00 +0000
+++ plugins/RemoteControl/src/AbstractAPIService.hpp 2016-06-12 13:59:22 +0000
@@ -0,0 +1,160 @@
1/*
2 * Stellarium Remote Control plugin
3 * Copyright (C) 2015 Florian Schaukowitsch
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 */
19
20#ifndef ABSTRACTAPISERVICE_HPP_
21#define ABSTRACTAPISERVICE_HPP_
22
23#include <QByteArray>
24#include <QMap>
25#include <QObject>
26
27//Uncomment to force each service to run in the HTTP handling threads themselves, like the initial versions
28//#define FORCE_THREADED_SERVICES
29
30class HttpResponse;
31class APIController;
32
33//! \addtogroup remoteControl
34//! @{
35
36//! Thread-safe version of HttpResponse that can be passed around through QMetaObject::invokeMethod.
37//! It contains the data that will be sent back to the client in the HTTP thread, when control returns to the APIController.
38struct APIServiceResponse
39{
40public:
41 //! Constructs an invalid response
42 APIServiceResponse() : status(-1)
43 {
44
45 }
46
47 //! Sets a specific HTTP header to the specified value
48 void setHeader(const QByteArray& name, const QByteArray& val);
49 //! Shortcut for int header values
50 void setHeader(const QByteArray& name, const int val);
51 //! Sets the HTTP status type and status text
52 void setStatus(int status, const QByteArray& text);
53
54 //! Replaces the current return data
55 void setData(const QByteArray& data);
56 //! Appends to the current return data
57 void appendData(const QByteArray& data);
58
59 //! Sets the HTTP status to 400, and sets the response data to the message
60 void writeRequestError(const QByteArray& msg);
61 //! Sets the Content-Type to "application/json" and serializes the given document
62 //! into JSON text format
63 void writeJSON(const QJsonDocument& doc);
64
65private:
66 int status;
67 QByteArray statusText;
68 QMap<QByteArray,QByteArray> headers;
69 QByteArray responseData;
70
71 //! Applies the data in this APIServiceResponse onto the HttpResponse
72 //! Must be called in the HTTP thread, done by APIController
73 void applyResponse(HttpResponse* response) const;
74
75 static int metaTypeId;
76 static int parametersMetaTypeId;
77 friend class APIController;
78
79};
80
81//! Defines the HTTP request parameters for the service
82typedef QMultiMap<QByteArray, QByteArray> APIParameters;
83
84Q_DECLARE_METATYPE(APIServiceResponse)
85Q_DECLARE_METATYPE(APIParameters)
86
87//! Abstract base class for all \ref remoteControl service implementations. Different implementations of this class are mapped to
88//! different HTTP request paths. For each API request, the APIController finds out which service to use, and calls its get() or post() method.
89class AbstractAPIService : public QObject
90{
91 Q_OBJECT
92public:
93 //! Abstract constructor. The service name is used by the APIController for request path mapping.
94 AbstractAPIService(const QByteArray& serviceName, QObject* parent = 0) : QObject(parent), m_serviceName(serviceName)
95 {
96
97 }
98
99 virtual ~AbstractAPIService() { }
100
101 //! Returns the service name, used for request path mapping by the APIController
102 QByteArray serviceName() { return m_serviceName; }
103
104 //! Return true if the service can safely be run in the HTTP handler thread,
105 //! instead of having to queue it into the Stellarium main thread.
106 //! Default implementation returns false, i.e. no special threading precautions have to be used
107 //! in the get() and post() implementation.
108 //! @warning If the macro \c FORCE_THREADED_SERVICES is set, all services will be run
109 //! in the HTTP threads for testing, and this method will be ignored.
110 virtual bool supportsThreadedOperation() const;
111
112 //! Called in the main thread each frame. Default implementation does nothing.
113 //! Can be used for ongoing actions, for example movement control.
114 virtual void update(double deltaTime);
115
116 //! Wrapper around getImpl(), constructs an APIServiceResponse object for the response and passes it on
117 //! @note The thread this is called in depends on the supportThreadedOperation() return value
118 Q_INVOKABLE APIServiceResponse get(const QByteArray &operation, const APIParameters &parameters);
119 //! Wrapper around postImpl(), constructs an APIServiceResponse object for the response and passes it on
120 //! @note The thread this is called in depends on the supportThreadedOperation() return value
121 Q_INVOKABLE APIServiceResponse post(const QByteArray &operation, const APIParameters &parameters, const QByteArray& data);
122
123protected:
124 //! Subclasses should implement this to define reactions to HTTP GET requests.
125 //! GET requests generally should only query data or program state, and not change it.
126 //! If there is an error with the request, use APIServiceResponse::writeRequestError to notify the client.
127 //! @param operation The operation string of the request (i.e. the part of the request URL after the service name, without parameters)
128 //! @param parameters The extracted service parameters (extracted from the URL)
129 //! @param response The response object, write your response into this
130 //! @note The thread this is called in depends on the supportThreadedOperation() return value
131 virtual void getImpl(const QByteArray& operation, const APIParameters& parameters, APIServiceResponse& response);
132 //! Subclasses should implement this to define reactions to HTTP POST requests.
133 //! POST requests generally should change data or perform some action.
134 //! If there is an error with the request, use APIServiceResponse::writeRequestError to notify the client.
135 //! @param operation The operation string of the request (i.e. the part of the request URL after the service name, without parameters)
136 //! @param parameters The extracted service parameters (extracted from the URL, and form data, if applicable)
137 //! @param data The unmodified data as sent from the client
138 //! @param response The response object, write your response into this
139 //! @note The thread this is called in depends on the supportThreadedOperation() return value
140 virtual void postImpl(const QByteArray& operation, const APIParameters& parameters, const QByteArray& data, APIServiceResponse& response);
141
142 //! This defines the connection type QMetaObject::invokeMethod has to use inside a service: either Qt::DirectConnection for main thread handling, or
143 //! Qt::BlockingQueuedConnection for HTTP thread handling
144 static const Qt::ConnectionType SERVICE_DEFAULT_INVOKETYPE;
145
146 //! Because the HTML descriptions in Stellarium are often not compatible
147 //! with "clean" HTML5 which is used for the main interface,
148 //! this method can be used to explicitely set the doctype
149 //! to 4.01 transitional for better results, and include the stylesheet
150 //! \c iframestyle.css
151 //! @param text The text to wrap with HTML document tags
152 //! @param title The title of the page
153 QString wrapHtml(QString& text, const QString& title) const;
154private:
155 QByteArray m_serviceName;
156};
157
158//! @}
159
160#endif
0161
=== added file 'plugins/RemoteControl/src/CMakeLists.txt'
--- plugins/RemoteControl/src/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ plugins/RemoteControl/src/CMakeLists.txt 2016-06-12 13:59:22 +0000
@@ -0,0 +1,78 @@
1INCLUDE_DIRECTORIES(. gui qtwebapp)
2LINK_DIRECTORIES(${BUILD_DIR}/src)
3
4SET(QtWebApp_SRCS
5 qtwebapp/httpserver/httpconnectionhandler.cpp
6 qtwebapp/httpserver/httpconnectionhandler.h
7 qtwebapp/httpserver/httpconnectionhandlerpool.cpp
8 qtwebapp/httpserver/httpconnectionhandlerpool.h
9 qtwebapp/httpserver/httpcookie.cpp
10 qtwebapp/httpserver/httpcookie.h
11 qtwebapp/httpserver/httpglobal.cpp
12 qtwebapp/httpserver/httpglobal.h
13 qtwebapp/httpserver/httplistener.cpp
14 qtwebapp/httpserver/httplistener.h
15 qtwebapp/httpserver/httprequest.cpp
16 qtwebapp/httpserver/httprequest.h
17 qtwebapp/httpserver/httprequesthandler.cpp
18 qtwebapp/httpserver/httprequesthandler.h
19 qtwebapp/httpserver/httpresponse.cpp
20 qtwebapp/httpserver/httpresponse.h
21 qtwebapp/httpserver/staticfilecontroller.cpp
22 qtwebapp/httpserver/staticfilecontroller.h
23
24 qtwebapp/templateengine/template.cpp
25 qtwebapp/templateengine/template.h
26 qtwebapp/templateengine/templateglobal.h
27)
28
29SET(RemoteControl_SRCS
30 AbstractAPIService.hpp
31 AbstractAPIService.cpp
32 APIController.hpp
33 APIController.cpp
34 MainService.hpp
35 MainService.cpp
36 ObjectService.hpp
37 ObjectService.cpp
38 LocationService.hpp
39 LocationService.cpp
40 LocationSearchService.hpp
41 LocationSearchService.cpp
42 RemoteControl.hpp
43 RemoteControl.cpp
44 RequestHandler.hpp
45 RequestHandler.cpp
46 ScriptService.hpp
47 ScriptService.cpp
48 SimbadService.hpp
49 SimbadService.cpp
50 StelActionService.hpp
51 StelActionService.cpp
52 StelPropertyService.hpp
53 StelPropertyService.cpp
54 ViewService.hpp
55 ViewService.cpp
56 gui/RemoteControlDialog.hpp
57 gui/RemoteControlDialog.cpp
58)
59
60SET(RemoteControl_UIS
61 gui/remoteControlDialog.ui
62)
63
64QT5_WRAP_UI(RemoteControl_UIS_H ${RemoteControl_UIS})
65
66################# compiles resources files ############
67SET(RemoteControl_RES ../RemoteControl.qrc)
68QT5_ADD_RESOURCES(RemoteControl_RES_CXX ${RemoteControl_RES})
69
70SET(extLinkerOption ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${OPENGL_LIBRARIES})
71
72ADD_LIBRARY(RemoteControl-static STATIC ${RemoteControl_SRCS} ${RemoteControl_RES_CXX} ${RemoteControl_UIS_H} ${QtWebApp_SRCS})
73QT5_USE_MODULES(RemoteControl-static Core Network Widgets)
74# The library target "RemoteControl-static" has a default OUTPUT_NAME of "RemoteControl-static", so change it.
75SET_TARGET_PROPERTIES(RemoteControl-static PROPERTIES OUTPUT_NAME "RemoteControl")
76TARGET_LINK_LIBRARIES(RemoteControl-static ${extLinkerOption})
77SET_TARGET_PROPERTIES(RemoteControl-static PROPERTIES COMPILE_FLAGS "-DQT_STATICPLUGIN")
78ADD_DEPENDENCIES(AllStaticPlugins RemoteControl-static)
079
=== added file 'plugins/RemoteControl/src/LocationSearchService.cpp'
--- plugins/RemoteControl/src/LocationSearchService.cpp 1970-01-01 00:00:00 +0000
+++ plugins/RemoteControl/src/LocationSearchService.cpp 2016-06-12 13:59:22 +0000
@@ -0,0 +1,104 @@
1/*
2 * Stellarium Remote Control plugin
3 * Copyright (C) 2015 Florian Schaukowitsch
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 */
19
20#include "LocationSearchService.hpp"
21
22#include "StelApp.hpp"
23#include "StelCore.hpp"
24#include "StelModuleMgr.hpp"
25#include "StelLocationMgr.hpp"
26
27#include <QJsonArray>
28#include <QJsonDocument>
29#include <QJsonObject>
30#include <QRegExp>
31
32LocationSearchService::LocationSearchService(const QByteArray &serviceName, QObject *parent)
33 : AbstractAPIService(serviceName,parent), locMgr(LocationList())
34{
35 //this is run in the main thread
36 connect(&StelApp::getInstance().getLocationMgr(), SIGNAL(locationListChanged()), this, SLOT(mainLocationManagerUpdated()));
37 mainLocationManagerUpdated();
38}
39
40void LocationSearchService::mainLocationManagerUpdated()
41{
42 //this is run in the main thread
43 locMgrMutex.lock();
44 //copy the contents of the location manager
45 locMgr.setLocations(StelApp::getInstance().getLocationMgr().getAll());
46 locMgrMutex.unlock();
47}
48
49void LocationSearchService::getImpl(const QByteArray& operation, const APIParameters &parameters, APIServiceResponse &response)
50{
51 if(operation=="search")
52 {
53 //parameter must be named "term" to be compatible with jQuery UI autocomplete without further JS code
54 QString term = QString::fromUtf8(parameters.value("term"));
55
56 if(term.isEmpty())
57 {
58 response.writeRequestError("needs non-empty 'term' parameter");
59 return;
60 }
61
62 //the filtering in the app is provided by QSortFilterProxyModel in the view
63 //we dont have that luxury, but we make sure the filtering happens in the separate HTTP thread
64 locMgrMutex.lock();
65 LocationMap allItems = locMgr.getAllMap();
66 locMgrMutex.unlock();
67
68 QJsonArray results;
69 const QList<QString>& list = allItems.keys();
70
71 //use a regexp in wildcard mode, the app does the same
72 QRegExp exp(term,Qt::CaseInsensitive, QRegExp::Wildcard);
73
74 for(QList<QString>::const_iterator it = list.begin();it!=list.end();++it)
75 {
76 if(it->contains(exp))
77 results.append(*it);
78 }
79
80 response.writeJSON(QJsonDocument(results));
81 }
82 else if(operation=="nearby")
83 {
84 QString sPlanet = QString::fromUtf8(parameters.value("planet"));
85 QString sLatitude = QString::fromUtf8(parameters.value("latitude"));
86 QString sLongitude = QString::fromUtf8(parameters.value("longitude"));
87 QString sRadius = QString::fromUtf8(parameters.value("radius"));
88
89 float latitude = sLatitude.toFloat();
90 float longitude = sLongitude.toFloat();
91 float radius = sRadius.toFloat();
92
93 locMgrMutex.lock();
94 LocationMap results = locMgr.pickLocationsNearby(sPlanet,longitude,latitude,radius);
95 locMgrMutex.unlock();
96
97 response.writeJSON(QJsonDocument(QJsonArray::fromStringList(results.keys())));
98 }
99 else
100 {
101 //TODO some sort of service description?
102 response.writeRequestError("unsupported operation. GET: search,nearby");
103 }
104}
0105
=== added file 'plugins/RemoteControl/src/LocationSearchService.hpp'
--- plugins/RemoteControl/src/LocationSearchService.hpp 1970-01-01 00:00:00 +0000
+++ plugins/RemoteControl/src/LocationSearchService.hpp 2016-06-12 13:59:22 +0000
@@ -0,0 +1,58 @@
1/*
2 * Stellarium Remote Control plugin
3 * Copyright (C) 2015 Florian Schaukowitsch
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 */
19
20#ifndef LOCATIONSEARCHSERVICE_HPP_
21#define LOCATIONSEARCHSERVICE_HPP_
22
23#include "AbstractAPIService.hpp"
24#include "StelLocationMgr.hpp"
25#include <QMutex>
26
27//! @ingroup remoteControl
28//! Provides predefined location search functionality, using the StelLocationMgr.
29//!
30//! @see \ref rcLocationSearchService, LocationService
31//! @note This service supports threaded operation
32class LocationSearchService : public AbstractAPIService
33{
34 Q_OBJECT
35public:
36 LocationSearchService(const QByteArray& serviceName, QObject* parent = 0);
37
38 virtual ~LocationSearchService() {}
39
40 //! We work on a copy of the StelLocationMgr, to prevent hitches as the web user is typing
41 //! @returns true
42 bool supportsThreadedOperation() const Q_DECL_OVERRIDE { return true; }
43protected:
44 //! @brief Implements the GET method.
45 //! @see \ref rcLocationSearchServiceGET
46 virtual void getImpl(const QByteArray& operation,const APIParameters& parameters, APIServiceResponse& response) Q_DECL_OVERRIDE;
47private slots:
48 // connected to the main location manager in the main thread
49 void mainLocationManagerUpdated();
50private:
51 //the location mgr is actually copied to be used in HTTP threads without blocking the main app
52 StelLocationMgr locMgr;
53 QMutex locMgrMutex;
54};
55
56
57
58#endif
059
=== added file 'plugins/RemoteControl/src/LocationService.cpp'
--- plugins/RemoteControl/src/LocationService.cpp 1970-01-01 00:00:00 +0000
+++ plugins/RemoteControl/src/LocationService.cpp 2016-06-12 13:59:22 +0000
@@ -0,0 +1,258 @@
1/*
2 * Stellarium Remote Control plugin
3 * Copyright (C) 2015 Florian Schaukowitsch
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 */
19
20#include "LocationService.hpp"
21
22#include "StelApp.hpp"
23#include "StelCore.hpp"
24#include "StelFileMgr.hpp"
25#include "StelModuleMgr.hpp"
26#include "StelLocationMgr.hpp"
27#include "StelLocaleMgr.hpp"
28#include "StelTranslator.hpp"
29#include "SolarSystem.hpp"
30
31#include <QFileInfo>
32#include <QMimeDatabase>
33#include <QJsonArray>
34#include <QJsonDocument>
35#include <QJsonObject>
36#include <QStringListModel>
37
38LocationService::LocationService(const QByteArray &serviceName, QObject *parent) : AbstractAPIService(serviceName,parent)
39{
40 //this is run in the main thread
41 core = StelApp::getInstance().getCore();
42 locMgr = &StelApp::getInstance().getLocationMgr();
43 ssys = GETSTELMODULE(SolarSystem);
44}
45
46void LocationService::getImpl(const QByteArray& operation, const APIParameters &parameters, APIServiceResponse &response)
47{
48 if(operation=="list")
49 {
50 //for now, this does not return location objects (which would require a much larger data transfer), but only the location strings
51 //same as in the LocationDialog list
52
53 //TODO not fully thread safe
54 QJsonArray list = QJsonArray::fromStringList(QStringList(locMgr->getAllMap().keys()));
55
56 response.writeJSON(QJsonDocument(list));
57 }
58 else if(operation == "countrylist")
59 {
60 const StelTranslator& trans = *StelTranslator::globalTranslator;
61
62 QStringList allCountries = StelApp::getInstance().getLocaleMgr().getAllCountryNames();
63 QJsonArray list;
64 foreach(QString str, allCountries)
65 {
66 QJsonObject obj;
67 obj.insert("name",str);
68 obj.insert("name_i18n",trans.qtranslate(str));
69 list.append(obj);
70 }
71
72 response.writeJSON(QJsonDocument(list));
73 }
74 else if(operation == "planetlist")
75 {
76 const StelTranslator& trans = StelApp::getInstance().getLocaleMgr().getSkyTranslator();
77
78 QStringList allPlanets = ssys->getAllPlanetEnglishNames();
79 QJsonArray list;
80 foreach(QString str, allPlanets)
81 {
82 QJsonObject obj;
83 obj.insert("name",str);
84 obj.insert("name_i18n",trans.qtranslate(str));
85 list.append(obj);
86 }
87
88 response.writeJSON(QJsonDocument(list));
89 }
90 else if(operation=="planetimage")
91 {
92 //return the image file for the specified planet
93 //logic from LocationDialog
94
95 QString planet = QString::fromUtf8(parameters.value("planet"));
96
97 if(planet.isEmpty())
98 {
99 response.writeRequestError("requires 'planet' parameter");
100 return;
101 }
102
103
104 SolarSystem* ssm = GETSTELMODULE(SolarSystem);
105 PlanetP p = ssm->searchByEnglishName(planet);
106 if (p)
107 {
108 QString path = StelFileMgr::findFile("textures/"+p->getTextMapName());
109 QFile file(path);
110 if (path.isEmpty() || !file.exists())
111 {
112 response.setStatus(404,"not found");
113 response.setData("planet image not available");
114 qWarning() << "ERROR - could not find planet map for " << planet;
115 return;
116 }
117
118 QMimeType mime = QMimeDatabase().mimeTypeForFile(path);
119
120 if(file.open(QIODevice::ReadOnly))
121 {
122 //allow the image to be cached by browser (1 hour)
123 response.setHeader("Cache-Control","max-age="+QByteArray::number(60*60));
124 //response.setHeader("Content-Length",static_cast<int>(file.size()));
125 if(!mime.isDefault())
126 {
127 response.setHeader("Content-Type", mime.name().toLatin1());
128 }
129
130 //load and write data
131 response.setData(file.readAll());
132 }
133 else
134 {
135 response.setStatus(500,"internal server error");
136 response.setData("could not open image file");
137 }
138 }
139 else
140 {
141 response.setStatus(404,"not found");
142 response.setData("planet id not found");
143 qWarning() << "ERROR - could not find planet " << planet;
144 return;
145 }
146 }
147 else
148 {
149 //TODO some sort of service description?
150 response.writeRequestError("unsupported operation. GET: list, countrylist, planetlist, planetimage");
151 }
152}
153
154void LocationService::postImpl(const QByteArray& operation, const APIParameters &parameters, const QByteArray &data, APIServiceResponse &response)
155{
156 Q_UNUSED(data);
157
158 if (operation == "setlocationfields")
159 {
160 QString id = QString::fromUtf8(parameters.value("id"));
161
162 StelLocation loc;
163 if(!id.isEmpty())
164 {
165 //if an id is set, ignore everything else
166 //use an invoke here for reasons
167 QMetaObject::invokeMethod(locMgr,"locationForString",SERVICE_DEFAULT_INVOKETYPE,
168 Q_RETURN_ARG(StelLocation, loc),
169 Q_ARG(QString,id));
170
171 if(loc.isValid())
172 {
173 //set location
174 QMetaObject::invokeMethod(core, "moveObserverTo", SERVICE_DEFAULT_INVOKETYPE,
175 Q_ARG(StelLocation, loc),
176 Q_ARG(double,0.0) );
177
178 response.setData("ok");
179 return;
180 }
181 else
182 {
183 response.writeRequestError("invalid location id");
184 return;
185 }
186 }
187
188 //copy current loc
189 loc = core->getCurrentLocation();
190
191 //similar to StelScriptMainAPI::setObserverLocation
192 QString sLatitude = QString::fromUtf8(parameters.value("latitude"));
193 QString sLongitude = QString::fromUtf8(parameters.value("longitude"));
194 QString sAltitude = QString::fromUtf8(parameters.value("altitude"));
195
196 QString name = QString::fromUtf8(parameters.value("name"));
197 QString country = QString::fromUtf8(parameters.value("country"));
198 QString planet = QString::fromUtf8(parameters.value("planet"));
199
200 //check each field
201 bool doneSomething = false;
202 bool ok = false;
203 float latitude = sLatitude.toFloat(&ok);
204 if(ok && latitude != loc.latitude)
205 {
206 loc.latitude = latitude;
207 doneSomething = true;
208 }
209 float longitude = sLongitude.toFloat(&ok);
210 if(ok && longitude != loc.longitude)
211 {
212 loc.longitude = longitude;
213 doneSomething = true;
214 }
215 int altitude = sAltitude.toInt(&ok);
216 if(ok && altitude != loc.altitude)
217 {
218 loc.altitude = altitude;
219 doneSomething = true;
220 }
221 if(parameters.contains("name") && name != loc.name)
222 {
223 loc.name = name;
224 doneSomething = true;
225 }
226 if(!country.isEmpty() && country != loc.country)
227 {
228 loc.country = country;
229 doneSomething = true;
230 }
231
232 if(!planet.isEmpty() && loc.planetName != planet)
233 {
234 if(ssys->searchByName(planet))
235 {
236 //set planet
237 loc.planetName = planet;
238 doneSomething = true;
239 }
240 }
241
242 if(doneSomething)
243 {
244 //update the core
245 QMetaObject::invokeMethod(core,"moveObserverTo", SERVICE_DEFAULT_INVOKETYPE,
246 Q_ARG(StelLocation, loc),
247 Q_ARG(double, 0.0),
248 Q_ARG(double, 0.0));
249 }
250
251 response.setData("ok");
252 }
253 else
254 {
255 //TODO some sort of service description?
256 response.writeRequestError("unsupported operation. POST: setlocation, setlocationfields");
257 }
258}
0259
=== added file 'plugins/RemoteControl/src/LocationService.hpp'
--- plugins/RemoteControl/src/LocationService.hpp 1970-01-01 00:00:00 +0000
+++ plugins/RemoteControl/src/LocationService.hpp 2016-06-12 13:59:22 +0000
@@ -0,0 +1,56 @@
1/*
2 * Stellarium Remote Control plugin
3 * Copyright (C) 2015 Florian Schaukowitsch
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 */
19
20#ifndef LOCATIONSERVICE_HPP_
21#define LOCATIONSERVICE_HPP_
22
23#include "AbstractAPIService.hpp"
24
25class StelCore;
26class StelLocationMgr;
27class SolarSystem;
28
29//! @ingroup remoteControl
30//! Provides methods to look up location-related information, and change the current location
31//!
32//! @see \ref rcLocationService, LocationService
33class LocationService : public AbstractAPIService
34{
35 Q_OBJECT
36public:
37 LocationService(const QByteArray& serviceName, QObject* parent = 0);
38
39 virtual ~LocationService() {}
40
41protected:
42 //! @brief Implements the HTTP GET requests
43 //! @see \ref rcLocationServiceGET
44 virtual void getImpl(const QByteArray& operation,const APIParameters& parameters, APIServiceResponse& response) Q_DECL_OVERRIDE;
45 //! @brief Implements the HTTP POST requests
46 //! @see \ref rcLocationServicePOST
47 virtual void postImpl(const QByteArray &operation, const APIParameters& parameters, const QByteArray &data, APIServiceResponse &response) Q_DECL_OVERRIDE;
48private:
49 StelCore* core;
50 StelLocationMgr* locMgr;
51 SolarSystem* ssys;
52};
53
54
55
56#endif
057
=== added file 'plugins/RemoteControl/src/MainService.cpp'
--- plugins/RemoteControl/src/MainService.cpp 1970-01-01 00:00:00 +0000
+++ plugins/RemoteControl/src/MainService.cpp 2016-06-12 13:59:22 +0000
@@ -0,0 +1,622 @@
1/*
2 * Stellarium Remote Control plugin
3 * Copyright (C) 2015 Florian Schaukowitsch
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 */
19
20#include "MainService.hpp"
21
22#include "StelApp.hpp"
23#include "StelActionMgr.hpp"
24#include "StelCore.hpp"
25#include "LandscapeMgr.hpp"
26#include "StelLocaleMgr.hpp"
27#include "StelMainView.hpp"
28#include "StelModuleMgr.hpp"
29#include "StelMovementMgr.hpp"
30#include "StelObjectMgr.hpp"
31#include "StelPropertyMgr.hpp"
32#include "StelScriptMgr.hpp"
33#include "StelSkyCultureMgr.hpp"
34#include "StelTranslator.hpp"
35#include "StelUtils.hpp"
36
37#include <QJsonDocument>
38
39
40MainService::MainService(const QByteArray &serviceName, QObject *parent)
41 : AbstractAPIService(serviceName,parent),
42 moveX(0),moveY(0),lastMoveUpdateTime(0)
43{
44 //100 should be more than enough
45 //this only has to emcompass events that occur between 2 status updates
46 actionCache.setCapacity(100);
47 propCache.setCapacity(100);
48
49 //this is run in the main thread
50 core = StelApp::getInstance().getCore();
51 actionMgr = StelApp::getInstance().getStelActionManager();
52 lsMgr = GETSTELMODULE(LandscapeMgr);
53 localeMgr = &StelApp::getInstance().getLocaleMgr();
54 objMgr = &StelApp::getInstance().getStelObjectMgr();
55 mvmgr = GETSTELMODULE(StelMovementMgr);
56 propMgr = StelApp::getInstance().getStelPropertyManager();
57 scriptMgr = &StelApp::getInstance().getScriptMgr();
58 skyCulMgr = &StelApp::getInstance().getSkyCultureMgr();
59
60 connect(actionMgr,SIGNAL(actionToggled(QString,bool)),this,SLOT(actionToggled(QString,bool)));
61 connect(propMgr,SIGNAL(stelPropChanged(QString,QVariant)),this,SLOT(propertyChanged(QString,QVariant)));
62
63 Q_ASSERT(this->thread()==objMgr->thread());
64}
65
66void MainService::update(double deltaTime)
67{
68 bool xZero = qFuzzyIsNull(moveX);
69 bool yZero = qFuzzyIsNull(moveY);
70
71 //prevent sudden disconnects from moving endlessly
72 if((QDateTime::currentMSecsSinceEpoch() - lastMoveUpdateTime) > 1000)
73 {
74 if(!xZero || !yZero)
75 qDebug()<<"[MainService] move timeout";
76 moveX = moveY = .0f;
77 }
78
79 //Similar to StelMovementMgr::updateMotion
80
81 if(!xZero || !yZero)
82 {
83 double currentFov = mvmgr->getCurrentFov();
84 // the more it is zoomed, the lower the moving speed is (in angle)
85 double depl=0.00025*deltaTime*1000*currentFov;
86
87 float deltaAz = moveX;
88 float deltaAlt = moveY;
89
90 if (deltaAz<0)
91 {
92 deltaAz = -depl/30;
93 if (deltaAz<-0.2)
94 deltaAz = -0.2;
95 }
96 else
97 {
98 if (deltaAz>0)
99 {
100 deltaAz = (depl/30);
101 if (deltaAz>0.2)
102 deltaAz = 0.2;
103 }
104 }
105
106 if (deltaAlt<0)
107 {
108 deltaAlt = -depl/30;
109 if (deltaAlt<-0.2)
110 deltaAlt = -0.2;
111 }
112 else
113 {
114 if (deltaAlt>0)
115 {
116 deltaAlt = depl/30;
117 if (deltaAlt>0.2)
118 deltaAlt = 0.2;
119 }
120 }
121
122 mvmgr->panView(deltaAz,deltaAlt);
123
124 //this is required to enable maximal fps for smoothness
125 StelMainView::getInstance().thereWasAnEvent();
126 }
127}
128
129void MainService::getImpl(const QByteArray& operation, const APIParameters &parameters, APIServiceResponse &response)
130{
131 if(operation=="status")
132 {
133 //a listing of the most common stuff that can change often
134
135 QString sActionId = QString::fromUtf8(parameters.value("actionId"));
136 bool actionOk;
137 int actionId = sActionId.toInt(&actionOk);
138
139 QString sPropId = QString::fromUtf8(parameters.value("propId"));
140 bool propOk;
141 int propId = sPropId.toInt(&propOk);
142
143 QJsonObject obj;
144
145 //// Location
146 const StelLocation& loc = core->getCurrentLocation();
147 {
148 QJsonObject obj2;
149 obj2.insert("name",loc.name);
150 obj2.insert("role",QString(loc.role));
151 obj2.insert("planet",loc.planetName);
152 obj2.insert("latitude",loc.latitude);
153 obj2.insert("longitude",loc.longitude);
154 obj2.insert("altitude",loc.altitude);
155 obj2.insert("country",loc.country);
156 obj2.insert("state",loc.state);
157 obj2.insert("landscapeKey",loc.landscapeKey);
158 obj.insert("location",obj2);
159 }
160
161 //// Time related stuff
162 {
163 double jday = core->getJD();
164 double deltaT = core->getDeltaT() * StelCore::JD_SECOND;
165
166 double gmtShift = localeMgr->getGMTShift(jday) / 24.0;
167
168 QString utcIso = StelUtils::julianDayToISO8601String(jday,true).append('Z');
169 QString localIso = StelUtils::julianDayToISO8601String(jday+gmtShift,true);
170
171 //time zone string
172 QString timeZone = localeMgr->getPrintableTimeZoneLocal(jday);
173
174 QJsonObject obj2;
175 obj2.insert("jday",jday);
176 obj2.insert("deltaT",deltaT);
177 obj2.insert("gmtShift",gmtShift);
178 obj2.insert("timeZone",timeZone);
179 obj2.insert("utc",utcIso);
180 obj2.insert("local",localIso);
181 obj2.insert("isTimeNow",core->getIsTimeNow());
182 obj2.insert("timerate",core->getTimeRate());
183 obj.insert("time",obj2);
184 }
185
186 //// Info about selected object (only primary)
187 {
188 QString infoStr;
189 QMetaObject::invokeMethod(this,"getInfoString",SERVICE_DEFAULT_INVOKETYPE,
190 Q_RETURN_ARG(QString,infoStr));
191 obj.insert("selectioninfo",infoStr);
192 }
193
194 //// Info about current view
195 {
196 QJsonObject obj2;
197
198 // the aim fov may lie outside the min/max bounds, so constrain it
199 double fov = mvmgr->getAimFov();
200 if(fov < mvmgr->getMinFov())
201 fov = mvmgr->getMinFov();
202 else if (fov>mvmgr->getMaxFov())
203 fov = mvmgr->getMaxFov();
204
205 obj2.insert("fov",fov);
206
207 obj.insert("view",obj2);
208 }
209
210 //// Info about changed actions & props (if requested)
211 {
212 if(actionOk)
213 obj.insert("actionChanges",getActionChangesSinceID(actionId));
214 if(propOk)
215 obj.insert("propertyChanges",getPropertyChangesSinceID(propId));
216 }
217
218 response.writeJSON(QJsonDocument(obj));
219 }
220 else if(operation=="plugins")
221 {
222 // Retrieve list of plugins
223
224 QJsonObject mainObj;
225
226 StelModuleMgr& modMgr = StelApp::getInstance().getModuleMgr();
227 foreach(const StelModuleMgr::PluginDescriptor& desc, modMgr.getPluginsList())
228 {
229 QJsonObject pluginObj,infoObj;
230 pluginObj.insert("loadAtStartup", desc.loadAtStartup);
231 pluginObj.insert("loaded", desc.loaded);
232
233 infoObj.insert("authors", desc.info.authors);
234 infoObj.insert("contact", desc.info.contact);
235 infoObj.insert("description", desc.info.description);
236 infoObj.insert("displayedName", desc.info.displayedName);
237 infoObj.insert("startByDefault", desc.info.startByDefault);
238 infoObj.insert("version", desc.info.version);
239
240 pluginObj.insert("info",infoObj);
241 mainObj.insert(desc.info.id, pluginObj);
242 }
243
244 response.writeJSON(QJsonDocument(mainObj));
245 }
246 else
247 {
248 //TODO some sort of service description?
249 response.writeRequestError("unsupported operation. GET: status, plugins");
250 }
251}
252
253void MainService::postImpl(const QByteArray& operation, const APIParameters &parameters, const QByteArray &data, APIServiceResponse &response)
254{
255 Q_UNUSED(data);
256
257 if(operation == "time")
258 {
259 bool doneSomething = false;
260 bool ok;
261
262 //set the time + timerate
263 {
264 const QByteArray& raw = parameters.value("time");
265 if(!raw.isEmpty())
266 {
267 //parse time and set it
268 double jday = QString(raw).toDouble(&ok);
269 if(ok)
270 {
271 //check for invalid double (NaN, inf...)
272 //this will crash the app if it is allowed
273 if(qIsNaN(jday) || qIsInf(jday))
274 {
275 qWarning()<<"[RemoteControl] Prevented setting invalid time"<<jday<<", does the web interface have a bug?";
276 response.setData("error: invalid time value");
277 return;
278 }
279
280 doneSomething = true;
281 //set new time
282 QMetaObject::invokeMethod(core,"setJD", SERVICE_DEFAULT_INVOKETYPE,
283 Q_ARG(double,jday));
284 }
285 }
286 }
287 {
288 const QByteArray& raw = parameters.value("timerate");
289 if(!raw.isEmpty())
290 {
291 //parse timerate and set it
292 double rate = QString(raw).toDouble(&ok);
293 if(ok)
294 {
295 doneSomething = true;
296 //set new time rate
297 QMetaObject::invokeMethod(core,"setTimeRate", SERVICE_DEFAULT_INVOKETYPE,
298 Q_ARG(double,rate));
299 }
300 }
301 }
302
303 if(doneSomething)
304 response.setData("ok");
305 else
306 response.setData("error: invalid parameters, use time/timerate as double values");
307 }
308 else if(operation == "focus")
309 {
310 QString target = QString::fromUtf8(parameters.value("target"));
311
312 //check target string first
313 if(target.isEmpty())
314 {
315 if(parameters.value("position").isEmpty())
316 {
317 //no parameters = clear focus
318 target = "";
319 }
320 else
321 {
322 //parse position
323 QJsonDocument doc = QJsonDocument::fromJson(parameters.value("position"));
324 QJsonArray arr = doc.array();
325 if(arr.size() == 3)
326 {
327 Vec3d pos;
328 pos[0] = arr.at(0).toDouble();
329 pos[1] = arr.at(1).toDouble();
330 pos[2] = arr.at(2).toDouble();
331
332 //deselect and move
333 QMetaObject::invokeMethod(this,"focusPosition", SERVICE_DEFAULT_INVOKETYPE,
334 Q_ARG(Vec3d,pos));
335 response.setData("ok");
336 return;
337 }
338
339 response.writeRequestError("invalid position format");
340 return;
341 }
342 }
343
344 bool result;
345 QMetaObject::invokeMethod(this,"focusObject",SERVICE_DEFAULT_INVOKETYPE,
346 Q_RETURN_ARG(bool,result),
347 Q_ARG(QString,target));
348
349 response.setData(result ? "true" : "false");
350 }
351 else if(operation == "move")
352 {
353 QString xs = QString::fromUtf8(parameters.value("x"));
354 QString ys = QString::fromUtf8(parameters.value("y"));
355
356 bool xOk,yOk;
357 float x = xs.toInt(&xOk);
358 float y = ys.toInt(&yOk);
359
360 if(xOk || yOk)
361 {
362 QMetaObject::invokeMethod(this,"updateMovement", SERVICE_DEFAULT_INVOKETYPE,
363 Q_ARG(float,x),
364 Q_ARG(float,y),
365 Q_ARG(bool,xOk),
366 Q_ARG(bool,yOk));
367
368 response.setData("ok");
369 }
370 else
371 response.writeRequestError("requires x or y parameter");
372 }
373 else if (operation == "fov")
374 {
375 QString fov = QString::fromUtf8(parameters.value("fov"));
376 bool ok;
377 double dFov = fov.toDouble(&ok);
378
379 if(fov.isEmpty() || !ok)
380 {
381 response.writeRequestError("requires fov parameter");
382 return;
383 }
384
385 QMetaObject::invokeMethod(this,"setFov",SERVICE_DEFAULT_INVOKETYPE,
386 Q_ARG(double,dFov));
387
388 response.setData("ok");
389 }
390 else
391 {
392 //TODO some sort of service description?
393 response.writeRequestError("unsupported operation. POST: time,focus,move,fov");
394 }
395}
396
397StelObjectP MainService::getSelectedObject()
398{
399 const QList<StelObjectP>& list = objMgr->getSelectedObject();
400 if(list.isEmpty())
401 return StelObjectP();
402 return list.first();
403}
404
405QString MainService::getInfoString()
406{
407 StelObjectP selectedObject = getSelectedObject();
408 if(selectedObject.isNull())
409 return QString();
410 return selectedObject->getInfoString(core,StelObject::AllInfo | StelObject::NoFont);
411}
412
413bool MainService::focusObject(const QString &name)
414{
415 //StelDialog::gotoObject
416
417 //if name is empty, unselect
418 if(name.isEmpty())
419 {
420 objMgr->unSelect();
421 return true;
422 }
423
424 bool result = false;
425 if (objMgr->findAndSelectI18n(name) || objMgr->findAndSelect(name))
426 {
427 const QList<StelObjectP> newSelected = objMgr->getSelectedObject();
428 if (!newSelected.empty())
429 {
430 // Can't point to home planet
431 if (newSelected[0]->getEnglishName()!=core->getCurrentLocation().planetName)
432 {
433 mvmgr->moveToObject(newSelected[0], mvmgr->getAutoMoveDuration());
434 mvmgr->setFlagTracking(true);
435 result = true;
436 }
437 else
438 {
439 objMgr->unSelect();
440 }
441 }
442 }
443 return result;
444}
445
446void MainService::focusPosition(const Vec3d &pos)
447{
448 objMgr->unSelect();
449 mvmgr->moveToJ2000(pos, mvmgr->getAutoMoveDuration());
450}
451
452void MainService::updateMovement(float x, float y, bool xUpdated, bool yUpdated)
453{
454 if(xUpdated)
455 {
456 this->moveX = x;
457 }
458 if(yUpdated)
459 {
460 this->moveY = y;
461 }
462 qint64 curTime = QDateTime::currentMSecsSinceEpoch();
463 //qDebug()<<"updateMove"<<x<<y<<(curTime-lastMoveUpdateTime);
464 lastMoveUpdateTime = curTime;
465}
466
467void MainService::setFov(double fov)
468{
469 //TODO calculate a better move duration here
470 mvmgr->zoomTo(fov,0.25f);
471}
472
473void MainService::actionToggled(const QString &id, bool val)
474{
475 actionMutex.lock();
476 actionCache.append(ActionCacheEntry(id,val));
477 if(!actionCache.areIndexesValid())
478 {
479 //in theory, this can happen, but practically not so much
480 qWarning()<<"Action cache indices invalid";
481 actionCache.clear();
482 }
483 actionMutex.unlock();
484}
485
486void MainService::propertyChanged(const QString &id, const QVariant &val)
487{
488 propMutex.lock();
489 propCache.append(PropertyCacheEntry(id,val));
490 if(!propCache.areIndexesValid())
491 {
492 //in theory, this can happen, but practically not so much
493 qWarning()<<"Property cache indices invalid";
494 propCache.clear();
495 }
496 propMutex.unlock();
497}
498
499QJsonObject MainService::getActionChangesSinceID(int changeId)
500{
501 //changeId is the last id the interface is available
502 //or -2 if the interface just started
503 // -1 means the initial state was set
504
505 QJsonObject obj;
506 QJsonObject changes;
507 int newId = changeId;
508
509
510 actionMutex.lock();
511 if(actionCache.isEmpty())
512 {
513 if(changeId!=-1)
514 {
515 //this is either the initial state (-2) or
516 //something is "broken", probably from an existing web interface that reconnected after restart
517 //force a full reload
518
519 foreach(StelAction* ac, actionMgr->getActionList())
520 {
521 if(ac->isCheckable())
522 {
523 changes.insert(ac->getId(),ac->isChecked());
524 }
525 }
526 newId = -1;
527 }
528 }
529 else
530 {
531 if(changeId > actionCache.lastIndex() || changeId < (actionCache.firstIndex()-1))
532 {
533 //this is either the initial state (-2) or
534 //"broken" state again, force full reload
535 foreach(StelAction* ac, actionMgr->getActionList())
536 {
537 if(ac->isCheckable())
538 {
539 changes.insert(ac->getId(),ac->isChecked());
540 }
541 }
542 newId = actionCache.lastIndex();
543 }
544 else if(changeId < actionCache.lastIndex())
545 {
546 //create a "diff" between changeId to lastIndex
547 for(int i = changeId+1;i<=actionCache.lastIndex();++i)
548 {
549 const ActionCacheEntry& e = actionCache.at(i);
550 changes.insert(e.action,e.val);
551 }
552 newId = actionCache.lastIndex();
553 }
554 //else no changes happened, interface is at current state!
555 }
556 actionMutex.unlock();
557
558 obj.insert("changes",changes);
559 obj.insert("id",newId);
560
561 return obj;
562}
563
564QJsonObject MainService::getPropertyChangesSinceID(int changeId)
565{
566 //changeId is the last id the interface is available
567 //or -2 if the interface just started
568 // -1 means the initial state was set
569 QJsonObject obj;
570 QJsonObject changes;
571 int newId = changeId;
572
573 propMutex.lock();
574 if(propCache.isEmpty())
575 {
576 if(changeId!=-1)
577 {
578 //this is either the initial state (-2) or
579 //something is "broken", probably from an existing web interface that reconnected after restart
580 //force a full reload
581 const StelPropertyMgr::StelPropertyMap& map = propMgr->getPropertyMap();
582 for(StelPropertyMgr::StelPropertyMap::const_iterator it = map.constBegin();
583 it!=map.constEnd();++it)
584 {
585 changes.insert(it.key(), QJsonValue::fromVariant((*it)->getValue()));
586 }
587 newId = -1;
588 }
589 }
590 else
591 {
592 if(changeId > propCache.lastIndex() || changeId < (propCache.firstIndex()-1))
593 {
594 //this is either the initial state (-2) or
595 //"broken" state again, force full reload
596 const StelPropertyMgr::StelPropertyMap& map = propMgr->getPropertyMap();
597 for(StelPropertyMgr::StelPropertyMap::const_iterator it = map.constBegin();
598 it!=map.constEnd();++it)
599 {
600 changes.insert(it.key(), QJsonValue::fromVariant((*it)->getValue()));
601 }
602 newId = propCache.lastIndex();
603 }
604 else if(changeId < propCache.lastIndex())
605 {
606 //create a "diff" between changeId to lastIndex
607 for(int i = changeId+1;i<=propCache.lastIndex();++i)
608 {
609 const PropertyCacheEntry& e = propCache.at(i);
610 changes.insert(e.id,QJsonValue::fromVariant(e.val));
611 }
612 newId = propCache.lastIndex();
613 }
614 //else no changes happened, interface is at current state!
615 }
616 propMutex.unlock();
617
618 obj.insert("changes",changes);
619 obj.insert("id",newId);
620
621 return obj;
622}
0623
=== added file 'plugins/RemoteControl/src/MainService.hpp'
--- plugins/RemoteControl/src/MainService.hpp 1970-01-01 00:00:00 +0000
+++ plugins/RemoteControl/src/MainService.hpp 2016-06-12 13:59:22 +0000
@@ -0,0 +1,122 @@
1/*
2 * Stellarium Remote Control plugin
3 * Copyright (C) 2015 Florian Schaukowitsch
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 */
19
20#ifndef MAINSERVICE_HPP_
21#define MAINSERVICE_HPP_
22
23#include "AbstractAPIService.hpp"
24
25#include "StelObjectType.hpp"
26#include "VecMath.hpp"
27
28#include <QContiguousCache>
29#include <QJsonObject>
30#include <QMutex>
31
32class StelCore;
33class StelActionMgr;
34class LandscapeMgr;
35class StelLocaleMgr;
36class StelMovementMgr;
37class StelObjectMgr;
38class StelPropertyMgr;
39class StelScriptMgr;
40class StelSkyCultureMgr;
41
42//! @ingroup remoteControl
43//! Implements the main API services, including the \c status operation which can be repeatedly polled to find the current state of the main program,
44//! including time, view, location, StelAction and StelProperty state changes, movement, script status ...
45//!
46//! @see @ref rcMainService
47class MainService : public AbstractAPIService
48{
49 Q_OBJECT
50public:
51 MainService(const QByteArray& serviceName, QObject* parent = 0);
52
53 virtual ~MainService() {}
54
55 //! Used to implement move functionality
56 virtual void update(double deltaTime) Q_DECL_OVERRIDE;
57
58protected:
59 //! @brief Implements the GET operations
60 //! @see @ref rcMainServiceGET
61 virtual void getImpl(const QByteArray& operation,const APIParameters &parameters, APIServiceResponse& response) Q_DECL_OVERRIDE;
62 //! @brief Implements the HTTP POST operations
63 //! @see @ref rcMainServicePOST
64 virtual void postImpl(const QByteArray &operation, const APIParameters &parameters, const QByteArray &data, APIServiceResponse &response) Q_DECL_OVERRIDE;
65
66private slots:
67 StelObjectP getSelectedObject();
68
69 //! Returns the info string of the currently selected object
70 QString getInfoString();
71
72 //! Like StelDialog::gotoObject
73 bool focusObject(const QString& name);
74 void focusPosition(const Vec3d& pos);
75
76 void updateMovement(float x, float y, bool xUpdated, bool yUpdated);
77 void setFov(double fov);
78
79 void actionToggled(const QString& id, bool val);
80 void propertyChanged(const QString& id, const QVariant& val);
81
82private:
83 StelCore* core;
84 StelActionMgr* actionMgr;
85 LandscapeMgr* lsMgr;
86 StelLocaleMgr* localeMgr;
87 StelMovementMgr* mvmgr;
88 StelObjectMgr* objMgr;
89 StelPropertyMgr* propMgr;
90 StelScriptMgr* scriptMgr;
91 StelSkyCultureMgr* skyCulMgr;
92
93 float moveX,moveY;
94 qint64 lastMoveUpdateTime;
95
96 struct ActionCacheEntry
97 {
98 ActionCacheEntry(const QString& str,bool val) : action(str),val(val) {}
99 QString action;
100 bool val;
101 };
102
103 //lists the recently toggled actions - this is a pseudo-circular buffer
104 QContiguousCache<ActionCacheEntry> actionCache;
105 QMutex actionMutex;
106 QJsonObject getActionChangesSinceID(int changeId);
107
108 struct PropertyCacheEntry
109 {
110 PropertyCacheEntry(const QString& str, const QVariant& val) : id(str),val(val) {}
111 QString id;
112 QVariant val;
113 };
114 QContiguousCache<PropertyCacheEntry> propCache;
115 QMutex propMutex;
116 QJsonObject getPropertyChangesSinceID(int changeId);
117
118};
119
120
121
122#endif
0123
=== added file 'plugins/RemoteControl/src/ObjectService.cpp'
--- plugins/RemoteControl/src/ObjectService.cpp 1970-01-01 00:00:00 +0000
+++ plugins/RemoteControl/src/ObjectService.cpp 2016-06-12 13:59:22 +0000
@@ -0,0 +1,216 @@
1/*
2 * Stellarium Remote Control plugin
3 * Copyright (C) 2015 Florian Schaukowitsch
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 */
19
20#include "ObjectService.hpp"
21
22#include "SearchDialog.hpp"
23#include "StelApp.hpp"
24#include "StelCore.hpp"
25#include "StelObjectMgr.hpp"
26#include "StelTranslator.hpp"
27
28#include <QEventLoop>
29#include <QJsonArray>
30#include <QJsonDocument>
31#include <QJsonObject>
32#include <QSettings>
33#include <QMutex>
34#include <QThreadPool>
35#include <QRunnable>
36#include <QWaitCondition>
37
38ObjectService::ObjectService(const QByteArray &serviceName, QObject *parent) : AbstractAPIService(serviceName,parent)
39{
40 //this is run in the main thread
41 core = StelApp::getInstance().getCore();
42 objMgr = &StelApp::getInstance().getStelObjectMgr();
43 useStartOfWords = StelApp::getInstance().getSettings()->value("search/flag_start_words", false).toBool();
44}
45
46QStringList ObjectService::performSearch(const QString &text)
47{
48 //perform substitution greek text --> symbol
49 QString greekText = substituteGreek(text);
50
51 QStringList matches;
52 if(greekText != text) {
53 matches = objMgr->listMatchingObjectsI18n(text, 3, useStartOfWords);
54 matches += objMgr->listMatchingObjects(text, 3, useStartOfWords);
55 matches += objMgr->listMatchingObjectsI18n(greekText, (8 - matches.size()), useStartOfWords);
56 } else {
57 //no greek replaced, saves 1 call
58 matches = objMgr->listMatchingObjectsI18n(text, 5, useStartOfWords);
59 matches += objMgr->listMatchingObjects(text, 5, useStartOfWords);
60 }
61
62 return matches;
63}
64
65QString ObjectService::substituteGreek(const QString &text)
66{
67 //use the searchdialog static method for that
68 return SearchDialog::substituteGreek(text);
69}
70
71void ObjectService::getImpl(const QByteArray& operation, const APIParameters &parameters, APIServiceResponse &response)
72{
73 //make sure the object still "lives" in the main Stel thread, even though
74 //we may currently be in the HTTP thread
75 Q_ASSERT(this->thread() == objMgr->thread());
76
77 if(operation=="find")
78 {
79 //this may contain greek or other unicode letters
80 QString str = QString::fromUtf8(parameters.value("str"));
81 str = str.trimmed().toLower();
82
83 if(str.isEmpty())
84 {
85 response.writeRequestError("empty search string");
86 return;
87 }
88
89 //qDebug()<<"Search string"<<str;
90
91 QStringList results;
92 QMetaObject::invokeMethod(this,"performSearch",SERVICE_DEFAULT_INVOKETYPE,
93 Q_RETURN_ARG(QStringList,results),
94 Q_ARG(QString,str));
95
The diff has been truncated for viewing.