Merge lp:~daggerstab/stellarium/comets-asteroids-importer into lp:stellarium

Proposed by Bogdan Marinov on 2010-11-16
Status: Merged
Merged at revision: 4799
Proposed branch: lp:~daggerstab/stellarium/comets-asteroids-importer
Merge into: lp:stellarium
Diff against target: 7637 lines (+7199/-32)
36 files modified
CMakeLists.txt (+1/-0)
Doxyfile.cmake (+1/-1)
data/gui/nightStyle.css (+8/-0)
data/gui/normalStyle.css (+8/-0)
data/ssystem.ini (+10/-5)
plugins/CMakeLists.txt (+3/-0)
plugins/SolarSystemEditor/CMakeLists.txt (+19/-0)
plugins/SolarSystemEditor/UnpackProvisionalDesignation.pro (+12/-0)
plugins/SolarSystemEditor/src/CMakeLists.txt (+76/-0)
plugins/SolarSystemEditor/src/SolarSystemEditor.cpp (+1535/-0)
plugins/SolarSystemEditor/src/SolarSystemEditor.hpp (+312/-0)
plugins/SolarSystemEditor/src/gui/MPCImporterDialogPrototype02.ui (+171/-0)
plugins/SolarSystemEditor/src/gui/ManualImportWindow.cpp (+257/-0)
plugins/SolarSystemEditor/src/gui/ManualImportWindow.hpp (+79/-0)
plugins/SolarSystemEditor/src/gui/MpcImportWindow.cpp (+958/-0)
plugins/SolarSystemEditor/src/gui/MpcImportWindow.hpp (+135/-0)
plugins/SolarSystemEditor/src/gui/SolarSystemManagerWindow.cpp (+170/-0)
plugins/SolarSystemEditor/src/gui/SolarSystemManagerWindow.hpp (+73/-0)
plugins/SolarSystemEditor/src/gui/manualImportWindow.ui (+890/-0)
plugins/SolarSystemEditor/src/gui/mpcImportWindow.ui (+679/-0)
plugins/SolarSystemEditor/src/gui/solarSystemManagerWindow.ui (+426/-0)
plugins/SolarSystemEditor/src/gui/solarSystemManagerWindow_prototype01.ui (+130/-0)
plugins/SolarSystemEditor/ssystem_ini format.txt (+76/-0)
plugins/SolarSystemEditor/unpackProvisionalDesignationTest.cpp (+180/-0)
src/CMakeLists.txt (+9/-0)
src/StelMainGraphicsView.cpp (+4/-0)
src/core/StelFileMgr.cpp (+52/-0)
src/core/StelFileMgr.hpp (+7/-0)
src/core/modules/Comet.cpp (+171/-0)
src/core/modules/Comet.hpp (+83/-0)
src/core/modules/MinorPlanet.cpp (+296/-0)
src/core/modules/MinorPlanet.hpp (+113/-0)
src/core/modules/Planet.hpp (+1/-1)
src/core/modules/SolarSystem.cpp (+215/-24)
src/core/modules/SolarSystem.hpp (+15/-1)
src/translations.h (+24/-0)
To merge this branch: bzr merge lp:~daggerstab/stellarium/comets-asteroids-importer
Reviewer Review Type Date Requested Status
Fabien Chéreau 2010-11-16 Approve on 2010-11-17
Matthew Gates usage 2010-11-16 Pending
Review via email: mp+41004@code.launchpad.net

This proposal supersedes a proposal from 2010-11-12.

Description of the Change

This is the first version (0.0.1) of the Solar System Editor plug-in (formerly the Comets and Asteroids Importer plug-in).

It's not a complete Solar System editor yet - the window that would allow manual editing of all parameters of Solar System objects is not finished yet, so it is hidden in this release. You can open manualImportWindow.ui in QtDesigner for a preview of what it will look like.

In addition to the plug-in itself, the branch contains changes to Stellarium's core (SolarSystem + 2 new classes derived from Planet) that allow better handling of asteroids and comets, including name rendering and visual magnitude calculation.

Feel free to comment on the interface and the texts used in it. :)

Update: I've made several changes. The countdown has been removed (it's still used internally, but for connection timeout). The Solar System class now can skip invalid planet entries and does not crash when trying to load an invalid ssystem.ini file. See the summaries of the revisions for more information on what has been changed since the first merge proposal.

(I will look into using JSON for the Solar System, but I think this should happen after we release 0.10.6.)

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

At some point Mike Storm worked on an experimental JSON format for solar system objects. I think this was never merged, but it was superior to the old .ini format in that it could reflect natively nesting of objects.

See the mailing list archive thread:

http://sourceforge.net/mailarchive/forum.php?thread_name=c3fc7ff0812080257we37817fq7bb5e9f874c3a7ba%40mail.gmail.com&forum_name=stellarium-pubdevel

Matthew Gates (matthew-porpoisehead) wrote : Posted in a previous version of this proposal

First impressions - really good plugin - I think a lot of people will appreciate this one.

GUI:
1 Not sure if we need the path of the ssystem.ini printed. Perhaps just a "reset" option to delete user copy. I realize this won't if the ssystem.ini is messed up so much the program won't start, but then this message can't be seen, and for sure users won't remember it.

(2) If we don't have to have the big warning and path of user ssystem.ini, maybe we can also dispense with the Copy / Restore thing?

(3) Internet search timer somewhat annoying. It makes user wait for a minute if they /didn't/ find what they were looking for (at which point they will probably want to re-search straight away). Unless we get complaints of overloading from the search server people, I don't think we need the limit, although maybe we should set the user agent to something they can use to throttle us if they want rather than have a generic user agent (assuming we use http to connect).

(4) Maybe the search can just be a tab in the main window rather than a separate tab (if (1) & (2) are accepted, the first tab is not really necessary - just a restore button somewhere.

Just my 2 pence worth!

-

Minor bugs noticed:
- long names of downloaded objects get truncated to 20 characters.

review: Abstain (usage)
barrykgerdes (barrygastro) wrote : Posted in a previous version of this proposal

Hi

I compiled 4786 last night in Widows (4782 was OK). I causes a major lock up. It reaches the stellarium display and
then stops nothing but a total shut down unlocks the computer. As a restart then takes about 7 minutes I have not got very far but I suspect it may be in the config.ini or ssystem.ini files. The log.txt gives no indication

Barry Gerdes
Beaumont Hills Observatory
S 33' 41' 44" E 150' 56' 32"

> To: <email address hidden>
> From: <email address hidden>
> Subject: [Merge] lp:~daggerstab/stellarium/comets-asteroids-importer into lp:stellarium
> Date: Fri, 12 Nov 2010 17:23:10 +0000
>
> Bogdan Marinov has proposed merging lp:~daggerstab/stellarium/comets-asteroids-importer into lp:stellarium.
>
> Requested reviews:
> Stellarium (stellarium)
>
>
> This is the first version (0.0.1) of the Solar System Editor plug-in (formerly the Comets and Asteroids Importer plug-in).
>
> It's not a complete Solar System editor yet - the window that would allow manual editing of all parameters of Solar System objects is not finished yet, so it is hidden in this release. You can open manualImportWindow.ui in QtDesigner for a preview of what it will look like.
>
> In addition to the plug-in itself, the branch contains changes to Stellarium's core (SolarSystem + 2 new classes derived from Planet) that allow better handling of asteroids and comets, including name rendering and visual magnitude calculation.
>
> Feel free to comment on the interface and the texts used in it. :)
> --
> https://code.launchpad.net/~daggerstab/stellarium/comets-asteroids-importer/+merge/40744
> Your team Stellarium is requested to review the proposed merge of lp:~daggerstab/stellarium/comets-asteroids-importer into lp:stellarium.

Fabien Chéreau (xalioth) wrote :

Excellent and amazingly complete! I really like that you thought about the merge tool when importing new objects!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2010-11-08 15:26:58 +0000
3+++ CMakeLists.txt 2010-11-16 20:06:17 +0000
4@@ -136,6 +136,7 @@
5 SET(USE_PLUGIN_TEXTUSERINTERFACE 1 CACHE BOOL "Define whether the TextUserInterface plugin should be created.")
6 SET(USE_PLUGIN_TIMEZONECONFIGURATION 1 CACHE BOOL "Define whether the TimeZoneConfiguration plugin should be created.")
7 SET(USE_PLUGIN_VIRGO 0 CACHE BOOL "Define whether the VirGO plugin should be created.")
8+SET(USE_PLUGIN_SOLARSYSTEMEDITOR 1 CACHE BOOL "Define whether the Solar System Editor should be built.")
9
10 ########## Static plugins need to define includes and libraries
11 ########## for the compilation of Stellarium itself
12
13=== modified file 'Doxyfile.cmake'
14--- Doxyfile.cmake 2010-09-03 09:54:30 +0000
15+++ Doxyfile.cmake 2010-11-16 20:06:17 +0000
16@@ -463,7 +463,7 @@
17 # disable (NO) the deprecated list. This list is created by putting
18 # \deprecated commands in the documentation.
19
20-GENERATE_DEPRECATEDLIST= NO
21+GENERATE_DEPRECATEDLIST= YES
22
23 # The ENABLED_SECTIONS tag can be used to enable conditional
24 # documentation sections, marked by \if sectionname ... \endif.
25
26=== modified file 'data/gui/nightStyle.css'
27--- data/gui/nightStyle.css 2010-11-16 19:33:22 +0000
28+++ data/gui/nightStyle.css 2010-11-16 20:06:17 +0000
29@@ -514,6 +514,14 @@
30 image: url(:/graphicGui/nv_checkbox-unchecked.png);
31 }
32
33+QListWidget::indicator::checked {
34+ image: url(:/graphicGui/nv_checkbox-checked.png);
35+}
36+
37+QListWidget::indicator:unchecked {
38+ image: url(:/graphicGui/nv_checkbox-unchecked.png);
39+}
40+
41 /*QCheckBox:disabled {
42 color: rgb(210, 0, 0);
43 font-weight: 500;
44
45=== modified file 'data/gui/normalStyle.css'
46--- data/gui/normalStyle.css 2010-11-14 03:12:37 +0000
47+++ data/gui/normalStyle.css 2010-11-16 20:06:17 +0000
48@@ -513,6 +513,14 @@
49 image: url(:/graphicGui/checkbox-unchecked.png);
50 }
51
52+QListWidget::indicator::checked {
53+ image: url(:/graphicGui/checkbox-checked.png);
54+}
55+
56+QListWidget::indicator:unchecked {
57+ image: url(:/graphicGui/checkbox-unchecked.png);
58+}
59+
60 /*QCheckBox:disabled {
61 color: rgb(210, 0, 0);
62 font-weight: 500;
63
64=== modified file 'data/ssystem.ini'
65--- data/ssystem.ini 2010-07-16 14:09:25 +0000
66+++ data/ssystem.ini 2010-11-16 20:06:17 +0000
67@@ -586,8 +586,9 @@
68 albedo = 1
69 orbit_visualization_period = 365.25
70
71-[ceres]
72+[1ceres]
73 name = Ceres
74+minor_planet_number = 1
75 parent = Sun
76 radius = 470
77 oblateness = 0.0
78@@ -607,8 +608,9 @@
79 orbit_AscendingNode = 80.40696
80 orbit_Inclination = 10.58671
81
82-[pallas]
83+[2pallas]
84 name = Pallas
85+minor_planet_number = 2
86 parent = Sun
87 radius = 220
88 oblateness = 0.0
89@@ -628,8 +630,9 @@
90 orbit_AscendingNode = 173.13579
91 orbit_Inclination = 34.84182
92
93-[juno]
94+[3juno]
95 name = Juno
96+minor_planet_number = 3
97 parent = Sun
98 radius = 130
99 oblateness = 0.0
100@@ -649,8 +652,9 @@
101 orbit_AscendingNode = 170.12007
102 orbit_Inclination = 12.97036
103
104-[vesta]
105+[4vesta]
106 name = Vesta
107+minor_planet_number = 4
108 parent = Sun
109 radius = 280
110 oblateness = 0.0
111@@ -670,8 +674,9 @@
112 orbit_AscendingNode = 103.91841
113 orbit_Inclination = 7.13380
114
115-[eris]
116+[136199eris]
117 name = Eris
118+minor_planet_number = 136199
119 parent = Sun
120 radius = 1300
121 oblateness = 0.0
122
123=== modified file 'plugins/CMakeLists.txt'
124--- plugins/CMakeLists.txt 2010-11-08 15:24:12 +0000
125+++ plugins/CMakeLists.txt 2010-11-16 20:06:17 +0000
126@@ -41,3 +41,6 @@
127 SET(VIRGO_PROJECT_PATH "../extmodules/VirGO/" CACHE PATH "The location of the VirGO plugin main directory i.e. the one containing the top level CMakeLists.txt")
128 ADD_SUBDIRECTORY( ${VIRGO_PROJECT_PATH} VirGO )
129 ENDIF()
130+IF (USE_PLUGIN_SOLARSYSTEMEDITOR)
131+ ADD_SUBDIRECTORY( SolarSystemEditor )
132+ENDIF()
133
134=== added directory 'plugins/SolarSystemEditor'
135=== added file 'plugins/SolarSystemEditor/CMakeLists.txt'
136--- plugins/SolarSystemEditor/CMakeLists.txt 1970-01-01 00:00:00 +0000
137+++ plugins/SolarSystemEditor/CMakeLists.txt 2010-11-16 20:06:17 +0000
138@@ -0,0 +1,19 @@
139+
140+SET(SOLARSYSTEMEDITOR_MAJOR "0")
141+SET(SOLARSYSTEMEDITOR_MINOR "0")
142+SET(SOLARSYSTEMEDITOR_PATCH "1")
143+SET(SOLARSYSTEMEDITOR_VERSION "${SOLARSYSTEMEDITOR_MAJOR}.${SOLARSYSTEMEDITOR_MINOR}.${SOLARSYSTEMEDITOR_PATCH}")
144+
145+IF(APPLE)
146+ SET(CMAKE_INSTALL_PREFIX $ENV{HOME}/Library/Application\ Support/Stellarium)
147+ElSE(APPLE)
148+ SET(CMAKE_INSTALL_PREFIX $ENV{HOME}/.stellarium)
149+ENDIF(APPLE)
150+
151+ADD_DEFINITIONS(-DPLUGIN_VERSION="${SOLARSYSTEMEDITOR_VERSION}")
152+
153+ADD_SUBDIRECTORY( src )
154+
155+INSTALL(FILES DESTINATION "modules/SolarSystemEditor")
156+
157+
158
159=== added file 'plugins/SolarSystemEditor/UnpackProvisionalDesignation.pro'
160--- plugins/SolarSystemEditor/UnpackProvisionalDesignation.pro 1970-01-01 00:00:00 +0000
161+++ plugins/SolarSystemEditor/UnpackProvisionalDesignation.pro 2010-11-16 20:06:17 +0000
162@@ -0,0 +1,12 @@
163+#-------------------------------------------------
164+#
165+# Project created by QtCreator 2010-09-18T15:18:26
166+#
167+#-------------------------------------------------
168+
169+TARGET = UnpackProvisionalDesignation
170+CONFIG += qtestlib
171+CONFIG -= app_bundle
172+
173+
174+SOURCES += unpackProvisionalDesignationTest.cpp
175
176=== added directory 'plugins/SolarSystemEditor/src'
177=== added file 'plugins/SolarSystemEditor/src/CMakeLists.txt'
178--- plugins/SolarSystemEditor/src/CMakeLists.txt 1970-01-01 00:00:00 +0000
179+++ plugins/SolarSystemEditor/src/CMakeLists.txt 2010-11-16 20:06:17 +0000
180@@ -0,0 +1,76 @@
181+
182+INCLUDE_DIRECTORIES(
183+ ${CMAKE_BINARY_DIR}
184+ ${CMAKE_BINARY_DIR}/plugins/SolarSystemEditor/src
185+ ${CMAKE_BINARY_DIR}/plugins/SolarSystemEditor/src/gui
186+ . gui)
187+
188+LINK_DIRECTORIES(/src)
189+
190+SET(SolarSystemEditor_SRCS
191+ SolarSystemEditor.hpp
192+ SolarSystemEditor.cpp
193+ gui/SolarSystemManagerWindow.hpp
194+ gui/SolarSystemManagerWindow.cpp
195+ gui/MpcImportWindow.hpp
196+ gui/MpcImportWindow.cpp
197+ gui/ManualImportWindow.hpp
198+ gui/ManualImportWindow.cpp
199+ )
200+
201+SET(SolarSystemEditor_UIS
202+ gui/solarSystemManagerWindow.ui
203+ gui/mpcImportWindow.ui
204+ gui/manualImportWindow.ui
205+)
206+
207+QT4_WRAP_UI(SolarSystemEditor_UIS_H ${SolarSystemEditor_UIS})
208+
209+#SET(SolarSystemEditor_RES ../resources/resources.qrc)
210+#QT4_ADD_RESOURCES(SolarSystemEditor_RES_CXX ${SolarSystemEditor_RES})
211+
212+SET(SolarSystemEditor_MOC_HDRS
213+ gui/SolarSystemManagerWindow.hpp
214+ gui/MpcImportWindow.hpp
215+ gui/ManualImportWindow.hpp
216+ SolarSystemEditor.hpp
217+ )
218+
219+QT4_WRAP_CPP(SolarSystemEditor_MOC_SRCS ${SolarSystemEditor_MOC_HDRS})
220+
221+SET(extLinkerOption ${QT_LIBRARIES} ${OPENGL_LIBRARIES} ${ICONV_LIBRARIES} ${INTL_LIBRARIES})
222+
223+#Dynamic library
224+IF(BUILD_DYNAMIC_PLUGINS)
225+ ADD_LIBRARY(SolarSystemEditor MODULE ${SolarSystemEditor_SRCS} ${SolarSystemEditor_MOC_SRCS} ${SolarSystemEditor_RES_CXX} ${SolarSystemEditor_UIS_H})
226+
227+ IF(APPLE)
228+ FIND_LIBRARY(OPENGL_LIBRARY OpenGL)
229+ MARK_AS_ADVANCED(OPENGL_LIBRARY)
230+ SET_TARGET_PROPERTIES(SolarSystemEditor PROPERTIES LINK_FLAGS "-undefined dynamic_lookup" SUFFIX ".dylib")
231+ ENDIF(APPLE)
232+
233+ IF(WIN32)
234+ SET_TARGET_PROPERTIES(SolarSystemEditor PROPERTIES LINK_FLAGS "-enable-runtime-pseudo-reloc -Wl,--allow-multiple-definition" )
235+ SET(StelMain stelMain)
236+ ELSE(WIN32)
237+ SET(StelMain )
238+ ENDIF(WIN32)
239+
240+ TARGET_LINK_LIBRARIES(SolarSystemEditor ${StelMain} ${extLinkerOption})
241+
242+ INSTALL(TARGETS SolarSystemEditor DESTINATION "modules/SolarSystemEditor")
243+ENDIF()
244+
245+#Static library
246+IF(BUILD_STATIC_PLUGINS)
247+ ADD_LIBRARY(SolarSystemEditor-static STATIC ${SolarSystemEditor_SRCS} ${SolarSystemEditor_MOC_SRCS} ${SolarSystemEditor_RES_CXX} ${SolarSystemEditor_UIS_H})
248+ SET_TARGET_PROPERTIES(SolarSystemEditor-static PROPERTIES OUTPUT_NAME "SolarSystemEditor")
249+ TARGET_LINK_LIBRARIES(SolarSystemEditor-static ${extLinkerOption})
250+ IF(WIN32)
251+ SET_TARGET_PROPERTIES(SolarSystemEditor-static PROPERTIES COMPILE_FLAGS "-DQT_STATICPLUGIN")
252+ ELSE()
253+ SET_TARGET_PROPERTIES(SolarSystemEditor-static PROPERTIES COMPILE_FLAGS "-fPIC -DQT_STATICPLUGIN")
254+ ENDIF()
255+ ADD_DEPENDENCIES(AllStaticPlugins SolarSystemEditor-static)
256+ENDIF()
257
258=== added file 'plugins/SolarSystemEditor/src/SolarSystemEditor.cpp'
259--- plugins/SolarSystemEditor/src/SolarSystemEditor.cpp 1970-01-01 00:00:00 +0000
260+++ plugins/SolarSystemEditor/src/SolarSystemEditor.cpp 2010-11-16 20:06:17 +0000
261@@ -0,0 +1,1535 @@
262+/*
263+ * Solar System editor plug-in for Stellarium
264+ *
265+ * Copyright (C) 2010 Bogdan Marinov
266+ *
267+ * This program is free software; you can redistribute it and/or
268+ * modify it under the terms of the GNU General Public License
269+ * as published by the Free Software Foundation; either version 2
270+ * of the License, or (at your option) any later version.
271+ *
272+ * This program is distributed in the hope that it will be useful,
273+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
274+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
275+ * GNU General Public License for more details.
276+ *
277+ * You should have received a copy of the GNU General Public License
278+ * along with this program; if not, write to the Free Software
279+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
280+ */
281+
282+#include "SolarSystemEditor.hpp"
283+#include "SolarSystemManagerWindow.hpp"
284+
285+#include "StelApp.hpp"
286+#include "StelGui.hpp"
287+#include "StelGuiItems.hpp"
288+#include "StelFileMgr.hpp"
289+#include "StelIniParser.hpp"
290+#include "StelLocaleMgr.hpp"
291+#include "StelModuleMgr.hpp"
292+#include "StelObjectMgr.hpp"
293+#include "SolarSystem.hpp"
294+
295+#include <QDate>
296+#include <QDebug>
297+#include <QDir>
298+#include <QFile>
299+#include <QSettings>
300+#include <QString>
301+
302+#include <cmath>
303+#include <stdexcept>
304+
305+
306+StelModule* SolarSystemEditorStelPluginInterface::getStelModule() const
307+{
308+ return new SolarSystemEditor();
309+}
310+
311+StelPluginInfo SolarSystemEditorStelPluginInterface::getPluginInfo() const
312+{
313+ //Q_INIT_RESOURCE(solarSystemEditor);
314+
315+ StelPluginInfo info;
316+ info.id = "SolarSystemEditor";
317+ info.displayedName = "Solar System Editor";
318+ info.authors = "Bogdan Marinov";
319+ info.contact = "http://stellarium.org";
320+ info.description = "An interface for adding asteroids and comets to Stellarium. It can download object lists from the Minor Planet Center's website and perform searches in its online database. Still a work in progress.";
321+ return info;
322+}
323+
324+Q_EXPORT_PLUGIN2(SolarSystemEditor, SolarSystemEditorStelPluginInterface)
325+
326+SolarSystemEditor::SolarSystemEditor()
327+{
328+ setObjectName("SolarSystemEditor");
329+
330+ isInitialized = false;
331+ mainWindow = NULL;
332+ solarSystemConfigurationFile = NULL;
333+ solarSystemManager = GETSTELMODULE(SolarSystem);
334+
335+ //I really hope that the file manager is instantiated before this
336+ defaultSolarSystemFilePath = QFileInfo(StelFileMgr::getInstallationDir() + "/data/ssystem.ini").absoluteFilePath();
337+ customSolarSystemFilePath = QFileInfo(StelFileMgr::getUserDir() + "/data/ssystem.ini").absoluteFilePath();
338+}
339+
340+SolarSystemEditor::~SolarSystemEditor()
341+{
342+ if (solarSystemConfigurationFile != NULL)
343+ {
344+ delete solarSystemConfigurationFile;
345+ }
346+}
347+
348+void SolarSystemEditor::init()
349+{
350+ //Get a list of the "default" Solar System objects' names:
351+ //TODO: Use it as validation for the loading of the plug-in
352+ if (QFile::exists(defaultSolarSystemFilePath))
353+ {
354+ defaultSsoIdentifiers = listAllLoadedObjectsInFile(defaultSolarSystemFilePath);
355+ }
356+ else
357+ {
358+ //TODO: Better error message
359+ qDebug() << "Something is horribly wrong:" << StelFileMgr::getInstallationDir();
360+ return;
361+ }
362+
363+ try
364+ {
365+ //Make sure that a user ssystem.ini actually exists
366+ if (!cloneSolarSystemConfigurationFile())
367+ return;
368+
369+ mainWindow = new SolarSystemManagerWindow();
370+ }
371+ catch (std::runtime_error &e)
372+ {
373+ qWarning() << "init() error: " << e.what();
374+ return;
375+ }
376+
377+ isInitialized = true;
378+}
379+
380+void SolarSystemEditor::deinit()
381+{
382+ //
383+}
384+
385+void SolarSystemEditor::update(double) //deltaTime
386+{
387+ //
388+}
389+
390+void SolarSystemEditor::draw(StelCore*) //core
391+{
392+ //
393+}
394+
395+double SolarSystemEditor::getCallOrder(StelModuleActionName) const// actionName
396+{
397+ return 0.;
398+}
399+
400+bool SolarSystemEditor::configureGui(bool show)
401+{
402+ //If the plug-in has failed to initialize, disable the button
403+ //TODO: Display a message in the window instead.
404+ if (!isInitialized)
405+ return false;
406+
407+ if(show)
408+ {
409+ mainWindow->setVisible(true);
410+
411+ //Debugging block
412+ //if (cloneSolarSystemConfigurationFile())
413+ {
414+ //Import Encke for a start
415+ /*SsoElements SSO = readMpcOneLineCometElements("0002P 2010 08 6.5102 0.336152 0.848265 186.5242 334.5718 11.7843 20100104 11.5 6.0 2P/Encke MPC 59600");
416+ if (!appendToSolarSystemConfigurationFile(SSO))
417+ return true;
418+ */
419+
420+ //Import a list of comets on the desktop. The file is from
421+ //http://www.minorplanetcenter.org/iau/Ephemerides/Comets/Soft00Cmt.txt
422+ //It seems that some entries in the list don't match the described format
423+ /*QList<SsoElements> objectList = readMpcOneLineCometElementsFromFile(StelFileMgr::getDesktopDir() + "/Soft00Cmt.txt");
424+ if (!appendToSolarSystemConfigurationFile(objectList))
425+ return true;
426+ */
427+
428+ //Import Cruithne
429+ /*SsoElements asteroid = readMpcOneLineMinorPlanetElements("03753 15.6 0.15 K107N 205.95453 43.77037 126.27658 19.80793 0.5149179 0.98898552 0.9977217 3 MPO183459 488 28 1973-2010 0.58 M-h 3Eh MPC 0000 (3753) Cruithne 20100822");
430+ if (!appendToSolarSystemConfigurationFile(asteroid))
431+ return true;
432+ */
433+
434+ //Import a list of asteroids. The file is from
435+ //http://www.minorplanetcenter.org/iau/Ephemerides/Bright/2010/Soft00Bright.txt
436+ /*QList<SsoElements> objectList = readMpcOneLineMinorPlanetElementsFromFile(StelFileMgr::getDesktopDir() + "/Soft00Bright.txt");
437+ if (!appendToSolarSystemConfigurationFile(objectList))
438+ return true;*/
439+
440+ //Destroy and re-create the Solal System
441+ //solarSystemManager->reloadPlanets();
442+ }
443+ }
444+ return true;
445+}
446+
447+void SolarSystemEditor::updateI18n()
448+{
449+ //The Solar System MUST be translated before updating the window
450+ //TODO: Remove this if/when you merge this module in the Solar System module
451+ solarSystemManager->updateI18n();
452+
453+ if (mainWindow)
454+ {
455+ mainWindow->languageChanged();
456+ }
457+}
458+
459+bool SolarSystemEditor::cloneSolarSystemConfigurationFile()
460+{
461+ QDir userDataDirectory(StelFileMgr::getUserDir());
462+ if (!userDataDirectory.exists())
463+ {
464+ qDebug() << "Unable to find user data directory:" << userDataDirectory.absolutePath();
465+ return false;
466+ }
467+ if (!userDataDirectory.exists("data") && !userDataDirectory.mkdir("data"))
468+ {
469+ qDebug() << "Unable to create a \"data\" subdirectory in" << userDataDirectory.absolutePath();
470+ return false;
471+ }
472+
473+ if (QFile::exists(customSolarSystemFilePath))
474+ {
475+ qDebug() << "Using the ssystem.ini file that already exists in the user directory...";
476+ return true;
477+ }
478+
479+ if (QFile::exists(defaultSolarSystemFilePath))
480+ {
481+ qDebug() << "Trying to copy ssystem.ini to" << customSolarSystemFilePath;
482+ return QFile::copy(defaultSolarSystemFilePath, customSolarSystemFilePath);
483+ }
484+ else
485+ {
486+ qDebug() << "This should be impossible.";
487+ return false;
488+ }
489+}
490+
491+bool SolarSystemEditor::resetSolarSystemConfigurationFile()
492+{
493+ if (QFile::exists(customSolarSystemFilePath))
494+ {
495+ if (!QFile::remove((customSolarSystemFilePath)))
496+ {
497+ qWarning() << "Unable to delete" << customSolarSystemFilePath
498+ << endl << "Please remove the file manually.";
499+ return false;
500+ }
501+ }
502+
503+ return cloneSolarSystemConfigurationFile();
504+}
505+
506+void SolarSystemEditor::resetSolarSystemToDefault()
507+{
508+ if (isInitialized)
509+ {
510+ if (resetSolarSystemConfigurationFile())
511+ {
512+ //Deselect all currently selected objects
513+ StelObjectMgr * objectManager = GETSTELMODULE(StelObjectMgr);
514+ //TODO
515+ objectManager->unSelect();
516+
517+ solarSystemManager->reloadPlanets();
518+ emit solarSystemChanged();
519+ }
520+ }
521+}
522+
523+bool SolarSystemEditor::copySolarSystemConfigurationFileTo(QString filePath)
524+{
525+ if (QFile::exists(customSolarSystemFilePath))
526+ {
527+ QFileInfo targetFile(filePath);
528+ return QFile::copy(customSolarSystemFilePath, targetFile.absoluteFilePath());
529+ }
530+ else
531+ {
532+ return false;
533+ }
534+}
535+
536+bool SolarSystemEditor::replaceSolarSystemConfigurationFileWith(QString filePath)
537+{
538+ if (!QFile::exists(filePath))
539+ {
540+ //TODO: Message
541+ return false;
542+ }
543+
544+ //Is it a valid configuration file?
545+ QSettings settings(filePath, QSettings::IniFormat);
546+ if (settings.status() != QSettings::NoError)
547+ {
548+ qWarning() << filePath << "is not a valid configuration file.";
549+ return false;
550+ }
551+
552+ //Remove the existingfile
553+ if (QFile::exists(customSolarSystemFilePath))
554+ {
555+ if(!QFile::remove(customSolarSystemFilePath))
556+ {
557+ //TODO: Message
558+ return false;
559+ }
560+ }
561+
562+ //Copy the new file
563+ //If the copy fails, reset to the default configuration
564+ if (QFile::copy(filePath, customSolarSystemFilePath))
565+ {
566+ solarSystemManager->reloadPlanets();
567+ emit solarSystemChanged();
568+ return true;
569+ }
570+ else
571+ {
572+ //TODO: Message
573+ if (cloneSolarSystemConfigurationFile())
574+ {
575+ solarSystemManager->reloadPlanets();
576+ emit solarSystemChanged();
577+ return true;
578+ }
579+ else
580+ {
581+ //TODO: Message
582+ return false;
583+ }
584+ }
585+}
586+
587+QHash<QString,QString> SolarSystemEditor::listAllLoadedObjectsInFile(QString filePath)
588+{
589+ if (!QFile::exists(filePath))
590+ return QHash<QString,QString>();
591+
592+ QSettings solarSystem(filePath, QSettings::IniFormat);
593+ if (solarSystem.status() != QSettings::NoError)
594+ return QHash<QString,QString>();
595+
596+ QStringList groups = solarSystem.childGroups();
597+ QStringList planetNames = solarSystemManager->getAllPlanetEnglishNames();
598+ QHash<QString,QString> loadedObjects;
599+ foreach (QString group, groups)
600+ {
601+ QString name = solarSystem.value(group + "/name").toString();
602+ if (planetNames.contains(name))
603+ {
604+ loadedObjects.insert(name, group);
605+ }
606+ }
607+ return loadedObjects;
608+}
609+
610+QHash<QString,QString> SolarSystemEditor::listAllLoadedSsoIdentifiers()
611+{
612+ if (QFile::exists(customSolarSystemFilePath))
613+ {
614+ return listAllLoadedObjectsInFile(customSolarSystemFilePath);
615+ }
616+ else
617+ {
618+ //TODO: Error message
619+ return QHash<QString,QString>();
620+ }
621+}
622+
623+bool SolarSystemEditor::removeSsoWithName(QString name)
624+{
625+ if (name.isEmpty())
626+ return false;
627+
628+ //qDebug() << name;
629+ if (defaultSsoIdentifiers.keys().contains(name))
630+ {
631+ qWarning() << "You can't delete the default Solar System objects for the moment.";
632+ return false;
633+ }
634+
635+ //Make sure that the file exists
636+ if (!QFile::exists(customSolarSystemFilePath))
637+ {
638+ qDebug() << "Can't remove" << name << "to ssystem.ini: Unable to find" << customSolarSystemFilePath;
639+ return false;
640+ }
641+
642+ //Open the file
643+ QSettings settings(customSolarSystemFilePath, QSettings::IniFormat);
644+ if (settings.status() != QSettings::NoError)
645+ {
646+ qDebug() << "Error opening ssystem.ini:" << customSolarSystemFilePath;
647+ return false;
648+ }
649+
650+ //Remove the section
651+ foreach (QString group, settings.childGroups())
652+ {
653+ if (settings.value(group + "/name").toString() == name)
654+ {
655+ settings.remove(group);
656+ settings.sync();
657+ break;
658+ }
659+ }
660+
661+ //Deselect all currently selected objects
662+ //TODO: I bet that someone will complains, so: unselect only the removed one
663+ GETSTELMODULE(StelObjectMgr)->unSelect();
664+
665+ //Reload the Solar System
666+ solarSystemManager->reloadPlanets();
667+ emit solarSystemChanged();
668+
669+ return true;
670+}
671+
672+//TODO: Strings that have failed to be parsed. The usual source of discrepancies is
673+//http://www.minorplanetcenter.org/iau/Ephemerides/Comets/Soft00Cmt.txt
674+//It seems that some entries in the list don't match the described format.
675+/*
676+ " CJ95O010 1997 03 31.4141 0.906507 0.994945 130.5321 282.6820 89.3193 20100723 -2.0 4.0 C/1995 O1 (Hale-Bopp) MPC 61436" -> minus sign, fixed
677+ " CK09K030 2011 01 9.266 3.90156 1.00000 251.413 0.032 146.680 8.5 4.0 C/2009 K3 (Beshore) MPC 66205" -> lower precision than the spec, fixed
678+ " CK10F040 2010 04 6.109 0.61383 1.00000 120.718 237.294 89.143 13.5 4.0 C/2010 F4 (Machholz) MPC 69906" -> lower precision than the spec, fixed
679+ " CK10M010 2012 02 7.840 2.29869 1.00000 265.318 82.150 78.373 9.0 4.0 C/2010 M1 (Gibbs) MPC 70817" -> lower precision than the spec, fixed
680+ " CK10R010 2011 11 28.457 6.66247 1.00000 96.009 345.949 157.437 6.0 4.0 C/2010 R1 (LINEAR) MPEC 2010-R99" -> lower precision than the spec, fixed
681+ "0128P b 2007 06 13.8064 3.062504 0.320891 210.3319 214.3583 4.3606 20100723 8.5 4.0 128P/Shoemaker-Holt MPC 51822" -> fragment, fixed
682+ "0141P d 2010 05 29.7106 0.757809 0.749215 149.3298 246.0849 12.8032 20100723 12.0 12.0 141P/Machholz MPC 59599" -> fragment, fixed
683+*/
684+SsoElements SolarSystemEditor::readMpcOneLineCometElements(QString oneLineElements)
685+{
686+ SsoElements result;
687+
688+ QRegExp mpcParser("^\\s*(\\d{4})?([A-Z])((?:\\w{6}|\\s{6})?[0a-zA-Z])?\\s+(\\d{4})\\s+(\\d{2})\\s+(\\d{1,2}\\.\\d{3,4})\\s+(\\d{1,2}\\.\\d{5,6})\\s+(\\d\\.\\d{5,6})\\s+(\\d{1,3}\\.\\d{3,4})\\s+(\\d{1,3}\\.\\d{3,4})\\s+(\\d{1,3}\\.\\d{3,4})\\s+(?:(\\d{4})(\\d\\d)(\\d\\d))?\\s+(\\-?\\d{1,2}\\.\\d)\\s+(\\d{1,2}\\.\\d)\\s+(\\S.{1,54}\\S)(?:\\s+(\\S.*))?$");//
689+
690+ int match = mpcParser.indexIn(oneLineElements);
691+ //qDebug() << "RegExp captured:" << match << mpcParser.capturedTexts();
692+
693+ if (match < 0)
694+ {
695+ qWarning() << "No match for" << oneLineElements;
696+ return result;
697+ }
698+
699+ QString numberString = mpcParser.cap(1).trimmed();
700+ //QChar cometType = mpcParser.cap(2).at(0);
701+ QString provisionalDesignation = mpcParser.cap(3).trimmed();
702+
703+ if (numberString.isEmpty() && provisionalDesignation.isEmpty())
704+ {
705+ qWarning() << "Comet is missing both comet number AND provisional designation.";
706+ return result;
707+ }
708+
709+ QString name = mpcParser.cap(17).trimmed();
710+
711+ //Fragment suffix
712+ if (provisionalDesignation.length() == 1)
713+ {
714+ QChar fragmentIndex = provisionalDesignation.at(0);
715+ name.append(' ');
716+ name.append(fragmentIndex.toUpper());
717+ }
718+
719+ if (name.isEmpty())
720+ {
721+ return SsoElements();
722+ }
723+ result.insert("name", name);
724+
725+ QString sectionName = convertToGroupName(name);
726+ if (sectionName.isEmpty())
727+ {
728+ return SsoElements();
729+ }
730+ result.insert("section_name", sectionName);
731+
732+ //After a name has been determined, insert the essential keys
733+ result.insert("parent", "Sun");
734+ result.insert("type", "comet");
735+ //"comet_orbit" is used for all cases:
736+ //"ell_orbit" interprets distances as kilometers, not AUs
737+ result.insert("coord_func","comet_orbit");
738+
739+ result.insert("lighting", false);
740+ result.insert("color", "1.0, 1.0, 1.0");
741+ result.insert("tex_map", "nomap.png");
742+
743+ bool ok = false;
744+ //TODO: Use this for VALIDATION!
745+
746+ int year = mpcParser.cap(4).toInt();
747+ int month = mpcParser.cap(5).toInt();
748+ double dayFraction = mpcParser.cap(6).toDouble(&ok);
749+ int day = (int) dayFraction;
750+ QDate datePerihelionPassage(year, month, day);
751+ int fraction = (int) ((dayFraction - day) * 24 * 60 * 60);
752+ int seconds = fraction % 60; fraction /= 60;
753+ int minutes = fraction % 60; fraction /= 60;
754+ int hours = fraction % 24;
755+ //qDebug() << hours << minutes << seconds << fraction;
756+ QTime timePerihelionPassage(hours, minutes, seconds, 0);
757+ QDateTime dtPerihelionPassage(datePerihelionPassage, timePerihelionPassage, Qt::UTC);
758+ double jdPerihelionPassage = StelUtils::qDateTimeToJd(dtPerihelionPassage);
759+ result.insert("orbit_TimeAtPericenter", jdPerihelionPassage);
760+
761+ double perihelionDistance = mpcParser.cap(7).toDouble(&ok);//AU
762+ result.insert("orbit_PericenterDistance", perihelionDistance);
763+
764+ double eccentricity = mpcParser.cap(8).toDouble(&ok);//degrees
765+ result.insert("orbit_Eccentricity", eccentricity);
766+
767+ double argumentOfPerihelion = mpcParser.cap(9).toDouble(&ok);//J2000.0, degrees
768+ result.insert("orbit_ArgOfPericenter", argumentOfPerihelion);
769+
770+ double longitudeOfTheAscendingNode = mpcParser.cap(10).toDouble(&ok);//J2000.0, degrees
771+ result.insert("orbit_AscendingNode", longitudeOfTheAscendingNode);
772+
773+ double inclination = mpcParser.cap(11).toDouble(&ok);
774+ result.insert("orbit_Inclination", inclination);
775+
776+ double absoluteMagnitude = mpcParser.cap(15).toDouble(&ok);
777+ result.insert("absolute_magnitude", absoluteMagnitude);
778+
779+ //This is not the same "slope parameter" as used in asteroids. Better name?
780+ double slopeParameter = mpcParser.cap(16).toDouble(&ok);
781+ result.insert("slope_parameter", slopeParameter);
782+
783+ double radius = 5; //Fictitious
784+ result.insert("radius", radius);
785+ result.insert("albedo", 1);
786+
787+ return result;
788+}
789+
790+SsoElements SolarSystemEditor::readMpcOneLineMinorPlanetElements(QString oneLineElements)
791+{
792+ SsoElements result;
793+
794+ //This time I'll try splitting the line to columns, instead of
795+ //using a regular expression.
796+ //Using QString::mid() allows parsing it in a random sequence.
797+
798+ //Length validation
799+ if (oneLineElements.isEmpty() ||
800+ oneLineElements.length() > 202 ||
801+ oneLineElements.length() < 152) //The column ends at 160, but is left-aligned
802+ {
803+ return result;
804+ }
805+
806+ QString column;
807+ bool ok = false;
808+ //bool isLongForm = (oneLineElements.length() > 160) ? true : false;
809+
810+ //Minor planet number or provisional designation
811+ column = oneLineElements.mid(0, 7).trimmed();
812+ if (column.isEmpty())
813+ {
814+ return result;
815+ }
816+ int minorPlanetNumber = 0;
817+ QString provisionalDesignation;
818+ QString name;
819+ if (column.toInt(&ok) || ok)
820+ {
821+ minorPlanetNumber = column.toInt();
822+ }
823+ else
824+ {
825+ //See if it is a number, but packed
826+ //I hope the format is right (I've seen prefixes only between A and P)
827+ QRegExp packedMinorPlanetNumber("^([A-Za-z])(\\d+)$");
828+ if (packedMinorPlanetNumber.indexIn(column) == 0)
829+ {
830+ minorPlanetNumber = packedMinorPlanetNumber.cap(2).toInt(&ok);
831+ //TODO: Validation
832+ QChar prefix = packedMinorPlanetNumber.cap(1).at(0);
833+ if (prefix.isUpper())
834+ {
835+ minorPlanetNumber += ((10 + prefix.toAscii() - 'A') * 10000);
836+ }
837+ else
838+ {
839+ minorPlanetNumber += ((10 + prefix.toAscii() - 'a' + 26) * 10000);
840+ }
841+ }
842+ else
843+ {
844+ provisionalDesignation = unpackMinorPlanetProvisionalDesignation(column);
845+ }
846+ }
847+
848+ if (minorPlanetNumber)
849+ {
850+ name = QString::number(minorPlanetNumber);
851+ }
852+ else if(provisionalDesignation.isEmpty())
853+ {
854+ qDebug() << "readMpcOneLineMinorPlanetElements():"
855+ << column
856+ << "is not a valid number or packed provisional designation";
857+ return SsoElements();
858+ }
859+ else
860+ {
861+ name = provisionalDesignation;
862+ }
863+
864+ //In case the longer format is used, extract the human-readable name
865+ column = oneLineElements.mid(166, 28).trimmed();
866+ if (!column.isEmpty())
867+ {
868+ if (minorPlanetNumber)
869+ {
870+ QRegExp asteroidName("^\\((\\d+)\\)\\s+(\\S.+)$");
871+ if (asteroidName.indexIn(column) == 0)
872+ {
873+ name = asteroidName.cap(2);
874+ result.insert("minor_planet_number", minorPlanetNumber);
875+ }
876+ else
877+ {
878+ //Use the whole string, just in case
879+ name = column;
880+ }
881+ }
882+ //In the other case, the name is already the provisional designation
883+ }
884+ if (name.isEmpty())
885+ {
886+ return SsoElements();
887+ }
888+ result.insert("name", name);
889+
890+ //Section name
891+ QString sectionName = convertToGroupName(name, minorPlanetNumber);
892+ if (sectionName.isEmpty())
893+ {
894+ return SsoElements();
895+ }
896+ result.insert("section_name", sectionName);
897+
898+ //After a name has been determined, insert the essential keys
899+ result.insert("parent", "Sun");
900+ result.insert("type", "asteroid");
901+ //"comet_orbit" is used for all cases:
902+ //"ell_orbit" interprets distances as kilometers, not AUs
903+ result.insert("coord_func","comet_orbit");
904+
905+ result.insert("lighting", false);
906+ result.insert("color", "1.0, 1.0, 1.0");
907+ result.insert("tex_map", "nomap.png");
908+
909+ //Magnitude and slope parameter
910+ column = oneLineElements.mid(8,5).trimmed();
911+ double absoluteMagnitude = column.toDouble(&ok);
912+ if (!ok)
913+ return SsoElements();
914+ column = oneLineElements.mid(14,5).trimmed();
915+ double slopeParameter = column.toDouble(&ok);
916+ if (!ok)
917+ return SsoElements();
918+ result.insert("absolute_magnitude", absoluteMagnitude);
919+ result.insert("slope_parameter", slopeParameter);
920+
921+ //Orbital parameters
922+ column = oneLineElements.mid(37, 9).trimmed();
923+ double argumentOfPerihelion = column.toDouble(&ok);//J2000.0, degrees
924+ if (!ok)
925+ return SsoElements();
926+ result.insert("orbit_ArgOfPericenter", argumentOfPerihelion);
927+
928+ column = oneLineElements.mid(48, 9).trimmed();
929+ double longitudeOfTheAscendingNode = column.toDouble(&ok);//J2000.0, degrees
930+ if (!ok)
931+ return SsoElements();
932+ result.insert("orbit_AscendingNode", longitudeOfTheAscendingNode);
933+
934+ column = oneLineElements.mid(59, 9).trimmed();
935+ double inclination = column.toDouble(&ok);//J2000.0, degrees
936+ if (!ok)
937+ return SsoElements();
938+ result.insert("orbit_Inclination", inclination);
939+
940+ column = oneLineElements.mid(70, 9).trimmed();
941+ double eccentricity = column.toDouble(&ok);//degrees
942+ if (!ok)
943+ return SsoElements();
944+ result.insert("orbit_Eccentricity", eccentricity);
945+
946+ column = oneLineElements.mid(80, 11).trimmed();
947+ double meanDailyMotion = column.toDouble(&ok);//degrees per day
948+ if (!ok)
949+ return SsoElements();
950+ result.insert("orbit_MeanMotion", meanDailyMotion);
951+
952+ column = oneLineElements.mid(92, 11).trimmed();
953+ double semiMajorAxis = column.toDouble(&ok);
954+ if (!ok)
955+ return SsoElements();
956+ result.insert("orbit_SemiMajorAxis", semiMajorAxis);
957+
958+ column = oneLineElements.mid(20, 5).trimmed();//Epoch, in packed form
959+ QRegExp packedDateFormat("^([IJK])(\\d\\d)([1-9A-C])([1-9A-V])$");
960+ if (packedDateFormat.indexIn(column) != 0)
961+ {
962+ qDebug() << "readMpcOneLineMinorPlanetElements():"
963+ << column << "is not a date in packed format";
964+ return SsoElements();
965+ }
966+ int year = packedDateFormat.cap(2).toInt();
967+ switch (packedDateFormat.cap(1).at(0).toAscii())
968+ {
969+ case 'I':
970+ year += 1800;
971+ break;
972+ case 'J':
973+ year += 1900;
974+ break;
975+ case 'K':
976+ default:
977+ year += 2000;
978+ }
979+ int month = unpackDayOrMonthNumber(packedDateFormat.cap(3).at(0));
980+ int day = unpackDayOrMonthNumber(packedDateFormat.cap(4).at(0));
981+ //qDebug() << column << year << month << day;
982+ QDate epochDate(year, month, day);
983+ if (!epochDate.isValid())
984+ {
985+ qDebug() << "readMpcOneLineMinorPlanetElements():"
986+ << column << "unpacks to"
987+ << QString("%1-%2-%3").arg(year).arg(month).arg(day)
988+ << "This is not a valid date for an Epoch.";
989+ return SsoElements();
990+ }
991+ int epochJD = epochDate.toJulianDay();
992+ result.insert("orbit_Epoch", epochJD);
993+
994+ column = oneLineElements.mid(26, 9).trimmed();
995+ double meanAnomalyAtEpoch = column.toDouble(&ok);//degrees
996+ if (!ok)
997+ return SsoElements();
998+ result.insert("orbit_MeanAnomaly", meanAnomalyAtEpoch);
999+
1000+ //Radius and albedo
1001+ //Assume albedo of 0.15 and calculate a radius based on the absolute magnitude
1002+ //as described here: http://www.physics.sfasu.edu/astro/asteroids/sizemagnitude.html
1003+ double albedo = 0.15; //Assumed
1004+ double radius = std::ceil((1329 / std::sqrt(albedo)) * std::pow(10, -0.2 * absoluteMagnitude));
1005+ result.insert("albedo", albedo);
1006+ result.insert("radius", radius);
1007+
1008+ return result;
1009+}
1010+
1011+SsoElements SolarSystemEditor::readXEphemOneLineElements(QString oneLineElements)
1012+{
1013+ SsoElements result;
1014+
1015+ enum OrbitType {Elliptic, Hyperbolic, Parabolic} orbitType;
1016+
1017+ QStringList fields = oneLineElements.split(',');
1018+ if (fields.isEmpty() || fields.count() < 10 || fields.count() > 14)
1019+ return result;
1020+ //qDebug() << fields;
1021+
1022+ QString name = fields.at(0).trimmed();
1023+ if (name.isEmpty() || fields.at(1).isEmpty())
1024+ return result;
1025+
1026+ QChar orbitTypeFlag = fields.at(1).trimmed().at(0);
1027+ if (orbitTypeFlag == 'e')
1028+ orbitType = Elliptic;
1029+ else if(orbitTypeFlag == 'h')
1030+ orbitType = Hyperbolic;
1031+ else if (orbitTypeFlag == 'p')
1032+ orbitType = Parabolic;
1033+ else
1034+ {
1035+ qDebug() << "Unrecognised orbit type:" << orbitTypeFlag;
1036+ return result;
1037+ }
1038+
1039+ //"comet_orbit" is used for all cases:
1040+ //"ell_orbit" interprets distances as kilometers, not AUs
1041+ result.insert("coord_func", "comet_orbit");
1042+
1043+ //Type detection and name parsing
1044+ QString objectType;
1045+ int minorPlanetNumber = 0;
1046+ QRegExp cometProvisionalDesignationStart("^[PCDX]/");
1047+ QRegExp cometDesignationStart("^(\\d)+[PCDX]/");
1048+ if (cometDesignationStart.indexIn(name) == 0 ||
1049+ cometProvisionalDesignationStart.indexIn(name) == 0)
1050+ {
1051+ objectType = "comet";
1052+ }
1053+ else
1054+ {
1055+ objectType = "asteroid";
1056+ QRegExp asteroidProvisionalDesignation("(\\d{4}\\s[A-Z]{2})(\\d*)$");
1057+ int pdIndex = asteroidProvisionalDesignation.indexIn(name);
1058+ if (pdIndex != 0)
1059+ {
1060+ int spaceIndex = name.indexOf(' ');
1061+ if (spaceIndex > 0)
1062+ {
1063+ QString numberString = name.left(spaceIndex);
1064+ //qDebug() << numberString;
1065+ minorPlanetNumber = numberString.toInt();
1066+ if (minorPlanetNumber)
1067+ name = name.right(name.length() - spaceIndex - 1);
1068+ //qDebug() << name;
1069+ }
1070+ }
1071+ }
1072+ if (name.isEmpty())
1073+ {
1074+ return SsoElements();
1075+ }
1076+ result.insert("name", name);
1077+ result.insert("type", objectType);
1078+ if (minorPlanetNumber)
1079+ result.insert("minor_planet_number", minorPlanetNumber);
1080+
1081+ //Section name
1082+ QString sectionName = convertToGroupName(name, minorPlanetNumber);
1083+ if (sectionName.isEmpty())
1084+ {
1085+ return SsoElements();
1086+ }
1087+ result.insert("section_name", sectionName);
1088+
1089+ //After a name has been determined, insert the essential keys
1090+ result.insert("parent", "Sun");
1091+
1092+ result.insert("lighting", false);
1093+ result.insert("color", "1.0, 1.0, 1.0");
1094+ result.insert("tex_map", "nomap.png");
1095+
1096+ //Orbital elements
1097+ bool ok;
1098+ QString field;
1099+
1100+ if (orbitType == Elliptic)
1101+ field = fields.at(2);//Field 3
1102+ else
1103+ field = fields.at(3);//Field 4
1104+ double inclination = field.trimmed().toDouble(&ok);
1105+ if (!ok)
1106+ return SsoElements();
1107+ result.insert("orbit_Inclination", inclination);
1108+
1109+ if (orbitType == Elliptic)
1110+ field = fields.at(3);//Field 4
1111+ else if (orbitType == Hyperbolic)
1112+ field = fields.at(4);//Field 5
1113+ else
1114+ field = fields.at(6);//Field 7
1115+ double longitudeOfTheAscendingNode = field.toDouble(&ok);//J2000.0, degrees
1116+ if (!ok)
1117+ return SsoElements();
1118+ result.insert("orbit_AscendingNode", longitudeOfTheAscendingNode);
1119+
1120+ if (orbitType == Hyperbolic)
1121+ field = fields.at(5);//Field 6
1122+ else
1123+ field = fields.at(4);//Field 5
1124+ double argumentOfPerihelion = field.toDouble(&ok);//J2000.0, degrees
1125+ if (!ok)
1126+ return SsoElements();
1127+ result.insert("orbit_ArgOfPericenter", argumentOfPerihelion);
1128+
1129+ if (orbitType == Elliptic)
1130+ {
1131+ field = fields.at(5);//Field 6
1132+ double semiMajorAxis = field.toDouble(&ok);
1133+ if (!ok)
1134+ return SsoElements();
1135+ result.insert("orbit_SemiMajorAxis", semiMajorAxis);
1136+
1137+ field = fields.at(6);//Field 7
1138+ double meanDailyMotion = field.toDouble(&ok);//degrees per day
1139+ if (!ok)
1140+ return SsoElements();
1141+ result.insert("orbit_MeanMotion", meanDailyMotion);
1142+ }
1143+
1144+ double eccentricity;
1145+ if (orbitType == Elliptic)
1146+ eccentricity = fields.at(7).toDouble(&ok);//Field 8
1147+ else if (orbitType == Hyperbolic)
1148+ eccentricity = fields.at(6).toDouble(&ok);//Field 7
1149+ else
1150+ {
1151+ //Parabolic orbit
1152+ eccentricity = 1.0;
1153+ ok = true;
1154+ }
1155+ if (!ok)
1156+ return SsoElements();
1157+ result.insert("orbit_Eccentricity", eccentricity);
1158+
1159+ if (orbitType == Elliptic)
1160+ {
1161+ double meanAnomalyAtEpoch = fields.at(8).toDouble(&ok);//degrees
1162+ if (!ok)
1163+ return SsoElements();
1164+ result.insert("orbit_MeanAnomaly", meanAnomalyAtEpoch);
1165+ }
1166+
1167+ if (orbitType == Elliptic)
1168+ field = fields.at(9);//Field 10
1169+ else
1170+ field = fields.at(2);//Field 3
1171+ QStringList dateStrings = field.trimmed().split('/');
1172+ //TODO: Validation
1173+ int year = dateStrings.at(2).toInt();
1174+ int month = dateStrings.at(0).toInt();
1175+ double dayFraction = dateStrings.at(1).toDouble(&ok);
1176+ int day = (int) dayFraction;
1177+ QDate date(year, month, day);
1178+ int fraction = (int) ((dayFraction - day) * 24 * 60 * 60);
1179+ int seconds = fraction % 60; fraction /= 60;
1180+ int minutes = fraction % 60; fraction /= 60;
1181+ int hours = fraction % 24;
1182+ //qDebug() << hours << minutes << seconds << fraction;
1183+ QTime time(hours, minutes, seconds, 0);
1184+ QDateTime dt(date, time, Qt::UTC);
1185+ double jd = StelUtils::qDateTimeToJd(dt);
1186+ if (orbitType == Elliptic)
1187+ result.insert("orbit_Epoch", jd);
1188+ else
1189+ result.insert("orbit_TimeAtPericenter", jd);
1190+
1191+ if (orbitType != Elliptic)
1192+ {
1193+ if (orbitType == Hyperbolic)
1194+ field = fields.at(7);//Field 8
1195+ else
1196+ field = fields.at(5);//Field 6
1197+ double perihelionDistance = field.toDouble(&ok);//AU
1198+ if (!ok)
1199+ return SsoElements();
1200+ result.insert("orbit_PericenterDistance", perihelionDistance);
1201+ }
1202+
1203+ //Magnitude
1204+ if (orbitType == Elliptic)
1205+ field = fields.at(11);//Field 12
1206+ else if (orbitType == Hyperbolic)
1207+ field = fields.at(9);//Field 10
1208+ else
1209+ field = fields.at(8);//Field 9
1210+ QRegExp magnitudePrefix("^([Hg]\\s*)?(\\d.+)");
1211+ if (magnitudePrefix.indexIn(field) != 0)
1212+ return SsoElements();
1213+ field = magnitudePrefix.cap(2);
1214+ double absoluteMagnitude = field.toDouble(&ok);
1215+ if (!ok)
1216+ return SsoElements();
1217+ result.insert("absolute_magnitude", absoluteMagnitude);
1218+
1219+ if (orbitType == Elliptic)
1220+ field = fields.at(12);//Field 13
1221+ else if (orbitType == Hyperbolic)
1222+ field = fields.at(10);//Field 11
1223+ else
1224+ field = fields.at(9);//Field 10
1225+ double slopeParameter = field.toDouble(&ok);
1226+ if (!ok)
1227+ return SsoElements();
1228+ result.insert("slope_parameter", slopeParameter);
1229+
1230+ //Radius and albedo
1231+ double albedo = 0.04;
1232+ double radius = 5.0;
1233+ if (objectType == "asteroid")
1234+ {
1235+ //Assume albedo of 0.15 and calculate a radius based on the absolute magnitude
1236+ //http://www.physics.sfasu.edu/astro/asteroids/sizemagnitude.html
1237+ albedo = 0.15;
1238+ radius = std::ceil((1329 / std::sqrt(albedo)) * std::pow(10, -0.2 * absoluteMagnitude));
1239+ }
1240+ result.insert("albedo", albedo);
1241+ result.insert("radius", radius);
1242+
1243+ return result;
1244+}
1245+
1246+QList<SsoElements> SolarSystemEditor::readMpcOneLineCometElementsFromFile(QString filePath)
1247+{
1248+ QList<SsoElements> objectList;
1249+
1250+ if (!QFile::exists(filePath))
1251+ {
1252+ qDebug() << "Can't find" << filePath;
1253+ return objectList;
1254+ }
1255+
1256+ QFile mpcElementsFile(filePath);
1257+ if (mpcElementsFile.open(QFile::ReadOnly | QFile::Text ))//| QFile::Unbuffered
1258+ {
1259+ int candidatesCount = 0;
1260+ int lineCount = 0;
1261+
1262+ while(!mpcElementsFile.atEnd())
1263+ {
1264+ QString oneLineElements = QString(mpcElementsFile.readLine(200));
1265+ if(oneLineElements.endsWith('\n'))
1266+ {
1267+ oneLineElements.chop(1);
1268+ }
1269+ if (oneLineElements.isEmpty())
1270+ {
1271+ qDebug() << "Empty line skipped.";
1272+ continue;
1273+ }
1274+ lineCount++;
1275+
1276+ SsoElements ssObject = readMpcOneLineCometElements(oneLineElements);
1277+ if(!ssObject.isEmpty() && !ssObject.value("section_name").toString().isEmpty())
1278+ {
1279+ objectList << ssObject;
1280+ candidatesCount++;
1281+ }
1282+ }
1283+ mpcElementsFile.close();
1284+ qDebug() << "Done reading comet orbital elements."
1285+ << "Recognized" << candidatesCount << "candidate objects"
1286+ << "out of" << lineCount << "lines.";
1287+
1288+ return objectList;
1289+ }
1290+ else
1291+ {
1292+ qDebug() << "Unable to open for reading" << filePath;
1293+ qDebug() << "File error:" << mpcElementsFile.errorString();
1294+ return objectList;
1295+ }
1296+
1297+ return objectList;
1298+}
1299+
1300+QList<SsoElements> SolarSystemEditor::readMpcOneLineMinorPlanetElementsFromFile(QString filePath)
1301+{
1302+ QList<SsoElements> objectList;
1303+
1304+ if (!QFile::exists(filePath))
1305+ {
1306+ qDebug() << "Can't find" << filePath;
1307+ return objectList;
1308+ }
1309+
1310+ QFile mpcElementsFile(filePath);
1311+ if (mpcElementsFile.open(QFile::ReadOnly | QFile::Text ))//| QFile::Unbuffered
1312+ {
1313+ int candidatesCount = 0;
1314+ int lineCount = 0;
1315+
1316+ while(!mpcElementsFile.atEnd())
1317+ {
1318+ QString oneLineElements = QString(mpcElementsFile.readLine(202 + 2));//Allow for end-of-line characters
1319+ if(oneLineElements.endsWith('\n'))
1320+ {
1321+ oneLineElements.chop(1);
1322+ }
1323+ if (oneLineElements.isEmpty())
1324+ {
1325+ qDebug() << "Empty line skipped.";
1326+ continue;
1327+ }
1328+ lineCount++;
1329+
1330+ SsoElements ssObject = readMpcOneLineMinorPlanetElements(oneLineElements);
1331+ if(!ssObject.isEmpty() && !ssObject.value("section_name").toString().isEmpty())
1332+ {
1333+ objectList << ssObject;
1334+ candidatesCount++;
1335+ }
1336+ }
1337+ mpcElementsFile.close();
1338+ qDebug() << "Done reading minor planet orbital elements."
1339+ << "Recognized" << candidatesCount << "candidate objects"
1340+ << "out of" << lineCount << "lines.";
1341+
1342+ return objectList;
1343+ }
1344+ else
1345+ {
1346+ qDebug() << "Unable to open for reading" << filePath;
1347+ qDebug() << "File error:" << mpcElementsFile.errorString();
1348+ return objectList;
1349+ }
1350+
1351+ return objectList;
1352+}
1353+
1354+QList<SsoElements> SolarSystemEditor::readXEphemOneLineElementsFromFile(QString filePath)
1355+{
1356+ QList<SsoElements> objectList;
1357+
1358+ if (!QFile::exists(filePath))
1359+ {
1360+ qDebug() << "Can't find" << filePath;
1361+ return objectList;
1362+ }
1363+
1364+ QFile xEphemElementsFile(filePath);
1365+ if (xEphemElementsFile.open(QFile::ReadOnly | QFile::Text ))
1366+ {
1367+ int candidatesCount = 0;
1368+ int lineCount = 0;
1369+
1370+ while(!xEphemElementsFile.atEnd())
1371+ {
1372+ QString oneLineElements = QString(xEphemElementsFile.readLine());
1373+ if(oneLineElements.endsWith('\n'))
1374+ {
1375+ oneLineElements.chop(1);
1376+ }
1377+ if (oneLineElements.isEmpty())
1378+ {
1379+ qDebug() << "Empty line skipped.";
1380+ continue;
1381+ }
1382+ if (oneLineElements.startsWith('#'))
1383+ {
1384+ qDebug() << "Comment skipped.";
1385+ continue;
1386+ }
1387+ lineCount++;
1388+
1389+ SsoElements ssObject = readXEphemOneLineElements(oneLineElements);
1390+ if(!ssObject.isEmpty() && !ssObject.value("section_name").toString().isEmpty())
1391+ {
1392+ objectList << ssObject;
1393+ candidatesCount++;
1394+ }
1395+ }
1396+ xEphemElementsFile.close();
1397+ qDebug() << "Done reading minor planet orbital elements."
1398+ << "Recognized" << candidatesCount << "candidate objects"
1399+ << "out of" << lineCount << "lines.";
1400+
1401+ return objectList;
1402+ }
1403+ else
1404+ {
1405+ qDebug() << "Unable to open for reading" << filePath;
1406+ qDebug() << "File error:" << xEphemElementsFile.errorString();
1407+ return objectList;
1408+ }
1409+
1410+ return objectList;
1411+}
1412+
1413+bool SolarSystemEditor::appendToSolarSystemConfigurationFile(QList<SsoElements> objectList)
1414+{
1415+ if (objectList.isEmpty())
1416+ {
1417+ return false;
1418+ }
1419+
1420+ //Check if the configuration file exists
1421+ if (!QFile::exists(customSolarSystemFilePath))
1422+ {
1423+ qDebug() << "Can't append object data to ssystem.ini: Unable to find" << customSolarSystemFilePath;
1424+ return false;
1425+ }
1426+
1427+
1428+ QHash<QString,QString> loadedObjects = listAllLoadedSsoIdentifiers();
1429+
1430+ //Remove duplicates (identified by name, not by section name)
1431+ QSettings * solarSystemSettings = new QSettings(customSolarSystemFilePath, QSettings::IniFormat);
1432+ if (solarSystemSettings->status() != QSettings::NoError)
1433+ {
1434+ qDebug() << "Error opening ssystem.ini:" << customSolarSystemFilePath;
1435+ return false;
1436+ }
1437+ foreach (SsoElements object, objectList)
1438+ {
1439+ QString name = object.value("name").toString();
1440+ if (name.isEmpty())
1441+ continue;
1442+
1443+ QString group = object.value("section_name").toString();
1444+ if (group.isEmpty())
1445+ continue;
1446+
1447+ if (loadedObjects.contains(name))
1448+ {
1449+ solarSystemSettings->remove(loadedObjects.value(name));
1450+ loadedObjects.remove(name);
1451+ }
1452+ else if (solarSystemSettings->childGroups().contains(group))
1453+ {
1454+ loadedObjects.remove(solarSystemSettings->value(group + "/name").toString());
1455+ solarSystemSettings->remove(group);
1456+ }
1457+ }
1458+ solarSystemSettings->sync();
1459+ delete solarSystemSettings;
1460+ solarSystemSettings = NULL;
1461+
1462+ //Write to file
1463+ //TODO: The usual validation
1464+ qDebug() << "Appending to file...";
1465+ QFile solarSystemConfigurationFile(customSolarSystemFilePath);
1466+ if(solarSystemConfigurationFile.open(QFile::WriteOnly | QFile::Append | QFile::Text))
1467+ {
1468+ QTextStream output (&solarSystemConfigurationFile);
1469+ bool appendedAtLeastOne = false;
1470+
1471+ foreach (SsoElements object, objectList)
1472+ {
1473+ if (!object.contains("section_name"))
1474+ continue;
1475+
1476+ QString sectionName = object.value("section_name").toString();
1477+ if (sectionName.isEmpty())
1478+ continue;
1479+ object.remove("section_name");
1480+
1481+ QString name = object.value("name").toString();
1482+ if (name.isEmpty())
1483+ continue;
1484+
1485+ output << endl << QString("[%1]").arg(sectionName) << endl;
1486+ foreach(QString key, object.keys())
1487+ {
1488+ output << QString("%1 = %2").arg(key).arg(object.value(key).toString()) << endl;
1489+ }
1490+ output.flush();
1491+ qDebug() << "Appended successfully" << sectionName;
1492+ appendedAtLeastOne = true;
1493+ }
1494+
1495+ solarSystemConfigurationFile.close();
1496+ return appendedAtLeastOne;
1497+ }
1498+ else
1499+ {
1500+ qDebug() << "Unable to open for writing" << customSolarSystemFilePath;
1501+ return false;
1502+ }
1503+}
1504+
1505+bool SolarSystemEditor::appendToSolarSystemConfigurationFile(SsoElements object)
1506+{
1507+ if (!object.contains("section_name") || object.value("section_name").toString().isEmpty())
1508+ {
1509+ qDebug() << "appendToSolarSystemConfigurationFile(): Invalid object:" << object;
1510+ return false;
1511+ }
1512+
1513+ QList<SsoElements> list;
1514+ list << object;
1515+ return appendToSolarSystemConfigurationFile(list);
1516+}
1517+
1518+bool SolarSystemEditor::updateSolarSystemConfigurationFile(QList<SsoElements> objectList, UpdateFlags flags)
1519+{
1520+ if (objectList.isEmpty())
1521+ {
1522+ //Empty lists can be added without any problem. :)
1523+ qWarning() << "updateSolarSystemConfigurationFile(): The source list is empty.";
1524+ return true;
1525+ }
1526+
1527+ //Check if the configuration file exists
1528+ if (!QFile::exists(customSolarSystemFilePath))
1529+ {
1530+ qDebug() << "Can't update ssystem.ini: Unable to find" << customSolarSystemFilePath;
1531+ return false;
1532+ }
1533+
1534+ QSettings solarSystem(customSolarSystemFilePath, QSettings::IniFormat);
1535+ if (solarSystem.status() != QSettings::NoError)
1536+ {
1537+ qDebug() << "Error opening ssystem.ini:" << customSolarSystemFilePath;
1538+ return false;
1539+ }
1540+ QStringList existingSections = solarSystem.childGroups();
1541+ QHash<QString,QString> loadedObjects = listAllLoadedSsoIdentifiers();
1542+ //TODO: Move to contstructor?
1543+ QStringList orbitalElementsKeys;
1544+ orbitalElementsKeys << "coord_func"
1545+ << "orbit_ArgOfPericenter"
1546+ << "orbit_AscendingNode"
1547+ << "orbit_Eccentricity"
1548+ << "orbit_Epoch"
1549+ << "orbit_Inclination"
1550+ << "orbit_LongOfPericenter"
1551+ << "orbit_MeanAnomaly"
1552+ << "orbit_MeanLongitude"
1553+ << "orbit_MeanMotion"
1554+ << "orbit_PericenterDistance"
1555+ << "orbit_Period"
1556+ << "orbit_SemiMajorAxis"
1557+ << "orbit_TimeAtPericenter";
1558+
1559+ qDebug() << "Updating objects...";
1560+ foreach (SsoElements object, objectList)
1561+ {
1562+ QString name = object.value("name").toString();
1563+ if (name.isEmpty())
1564+ continue;
1565+
1566+ QString sectionName = object.value("section_name").toString();
1567+ if (sectionName.isEmpty())
1568+ continue;
1569+ object.remove("section_name");
1570+
1571+ if (loadedObjects.contains(name))
1572+ {
1573+ if (sectionName != loadedObjects.value(name))
1574+ {
1575+ //Is this a name conflict between an asteroid and a moon?
1576+ QString currentParent = solarSystem.value(loadedObjects.value(name) + "/parent").toString();
1577+ QString newParent = object.value("parent").toString();
1578+ if (newParent != currentParent)
1579+ {
1580+ name.append('*');
1581+ object.insert("name", name);
1582+
1583+ if (!existingSections.contains(sectionName))
1584+ {
1585+ solarSystem.beginGroup(sectionName);
1586+ foreach (QString property, object.keys())
1587+ {
1588+ solarSystem.setValue(property, object.value(property));
1589+ }
1590+ solarSystem.endGroup();
1591+ }
1592+ }
1593+ else
1594+ {
1595+ //If the parent is the same, update that object
1596+ sectionName = loadedObjects.value(name);
1597+ }
1598+ }
1599+ }
1600+ else
1601+ {
1602+ qDebug() << "Skipping update of" << sectionName << ", as no object with this name exists.";
1603+ continue;
1604+ }
1605+
1606+ solarSystem.beginGroup(sectionName);
1607+
1608+ if (flags.testFlag(UpdateNameAndNumber))
1609+ {
1610+ updateSsoProperty(solarSystem, object, "name");
1611+ updateSsoProperty(solarSystem, object, "minor_planet_number");
1612+ }
1613+
1614+ if (flags.testFlag(UpdateType))
1615+ {
1616+ updateSsoProperty(solarSystem, object, "type");
1617+ }
1618+
1619+ if (flags.testFlag(UpdateOrbitalElements))
1620+ {
1621+ //Remove all orbital elements first, in case
1622+ //the new ones use another coordinate function
1623+ foreach (QString key, orbitalElementsKeys)
1624+ {
1625+ solarSystem.remove(key);
1626+ }
1627+
1628+ foreach (QString key, orbitalElementsKeys)
1629+ {
1630+ updateSsoProperty(solarSystem, object, key);
1631+ }
1632+ }
1633+
1634+ if (flags.testFlag(UpdateMagnitudeParameters))
1635+ {
1636+ if (object.contains("absolute_magnitude") && object.contains("slope_parameter"))
1637+ {
1638+ QString type = solarSystem.value("type").toString();
1639+ if (type == "asteroid" || type == "comet" )
1640+ {
1641+ updateSsoProperty(solarSystem, object, "absolute_magnitude");
1642+ updateSsoProperty(solarSystem, object, "slope_parameter");
1643+ }
1644+ else
1645+ {
1646+ //TODO: Do what, log a message?
1647+ }
1648+ }
1649+ }
1650+
1651+ solarSystem.endGroup();
1652+ qDebug() << "Updated successfully" << sectionName;
1653+ }
1654+
1655+ return true;
1656+}
1657+
1658+void SolarSystemEditor::updateSsoProperty(QSettings & settings, SsoElements & properties, QString key)
1659+{
1660+ if (properties.contains(key))
1661+ {
1662+ settings.setValue(key, properties.value(key));
1663+ }
1664+}
1665+
1666+QString SolarSystemEditor::convertToGroupName(QString &name, int minorPlanetNumber)
1667+{
1668+ //TODO: Should I remove all non-alphanumeric, or only the obviously problematic?
1669+ QString groupName(name);
1670+ groupName.remove('\\');
1671+ groupName.remove('/');
1672+ groupName.remove('#');
1673+ groupName.remove(' ');
1674+ groupName.remove('-');
1675+ groupName = groupName.toLower();
1676+
1677+ //To prevent mix-up between asteroids and satellites:
1678+ //insert the minor planet number in the section name
1679+ //(if an asteroid is named, it must be numbered)
1680+ if (minorPlanetNumber)
1681+ {
1682+ groupName.prepend(QString::number(minorPlanetNumber));
1683+ }
1684+
1685+ return groupName;
1686+}
1687+
1688+int SolarSystemEditor::unpackDayOrMonthNumber(QChar digit)
1689+{
1690+ //0-9, 0 is an invalid value, but the function is supposed to return 0 on failure.
1691+ if (digit.isDigit())
1692+ {
1693+ return digit.digitValue();
1694+ }
1695+
1696+ if (digit.isUpper())
1697+ {
1698+ char letter = digit.toAscii();
1699+ if (letter < 'A' || letter > 'V')
1700+ return 0;
1701+ return (10 + (letter - 'A'));
1702+ }
1703+ else
1704+ {
1705+ return 0;
1706+ }
1707+}
1708+
1709+int SolarSystemEditor::unpackYearNumber (QChar prefix, int lastTwoDigits)
1710+{
1711+ int year = lastTwoDigits;
1712+ if (prefix == 'I')
1713+ year += 1800;
1714+ else if (prefix == 'J')
1715+ year += 1900;
1716+ else if (prefix == 'K')
1717+ year += 2000;
1718+ else
1719+ year = 0; //Error
1720+
1721+ return year;
1722+}
1723+
1724+//Can be used both for minor planets and comets with no additional modification,
1725+//as the regular expression for comets will match only capital letters.
1726+int SolarSystemEditor::unpackAlphanumericNumber (QChar prefix, int lastDigit)
1727+{
1728+ int cycleCount = lastDigit;
1729+ if (prefix.isDigit())
1730+ cycleCount += prefix.digitValue() * 10;
1731+ else if (prefix.isLetter() && prefix.isUpper())
1732+ cycleCount += (10 + prefix.toAscii() - QChar('A').toAscii()) * 10;
1733+ else if (prefix.isLetter() && prefix.isLower())
1734+ cycleCount += (10 + prefix.toAscii() - QChar('a').toAscii()) * 10 + 26*10;
1735+ else
1736+ cycleCount = 0; //Error
1737+
1738+ return cycleCount;
1739+}
1740+
1741+QString SolarSystemEditor::unpackMinorPlanetProvisionalDesignation (QString packedDesignation)
1742+{
1743+ QRegExp packedFormat("^([IJK])(\\d\\d)([A-Z])([\\dA-Za-z])(\\d)([A-Z])$");
1744+ if (packedFormat.indexIn(packedDesignation) != 0)
1745+ {
1746+ QRegExp packedSurveyDesignation("^(PL|T1|T2|T3)S(\\d+)$");
1747+ if (packedSurveyDesignation.indexIn(packedDesignation) == 0)
1748+ {
1749+ int number = packedSurveyDesignation.cap(2).toInt();
1750+ if (packedSurveyDesignation.cap(1) == "PL")
1751+ {
1752+ return QString("%1 P-L").arg(number);
1753+ }
1754+ else if (packedSurveyDesignation.cap(1) == "T1")
1755+ {
1756+ return QString("%1 T-1").arg(number);
1757+ }
1758+ else if (packedSurveyDesignation.cap(1) == "T2")
1759+ {
1760+ return QString("%1 T-2").arg(number);
1761+ }
1762+ else
1763+ {
1764+ return QString("%1 T-3").arg(number);
1765+ }
1766+ //TODO: Are there any other surveys?
1767+ }
1768+ else
1769+ {
1770+ return QString();
1771+ }
1772+ }
1773+
1774+ //Year
1775+ QChar yearPrefix = packedFormat.cap(1).at(0);
1776+ int yearLastTwoDigits = packedFormat.cap(2).toInt();
1777+ int year = unpackYearNumber(yearPrefix, yearLastTwoDigits);
1778+
1779+ //Letters
1780+ QString halfMonthLetter = packedFormat.cap(3);
1781+ QString secondLetter = packedFormat.cap(6);
1782+
1783+ //Second letter cycle count
1784+ QChar cycleCountPrefix = packedFormat.cap(4).at(0);
1785+ int cycleCountLastDigit = packedFormat.cap(5).toInt();
1786+ int cycleCount = unpackAlphanumericNumber(cycleCountPrefix, cycleCountLastDigit);
1787+
1788+ //Assemble the unpacked provisional designation
1789+ QString result = QString("%1 %2%3").arg(year).arg(halfMonthLetter).arg(secondLetter);
1790+ if (cycleCount != 0)
1791+ {
1792+ result.append(QString::number(cycleCount));
1793+ }
1794+
1795+ return result;
1796+}
1797
1798=== added file 'plugins/SolarSystemEditor/src/SolarSystemEditor.hpp'
1799--- plugins/SolarSystemEditor/src/SolarSystemEditor.hpp 1970-01-01 00:00:00 +0000
1800+++ plugins/SolarSystemEditor/src/SolarSystemEditor.hpp 2010-11-16 20:06:17 +0000
1801@@ -0,0 +1,312 @@
1802+/*
1803+ * Solar System editor plug-in for Stellarium
1804+ *
1805+ * Copyright (C) 2010 Bogdan Marinov
1806+ *
1807+ * This program is free software; you can redistribute it and/or
1808+ * modify it under the terms of the GNU General Public License
1809+ * as published by the Free Software Foundation; either version 2
1810+ * of the License, or (at your option) any later version.
1811+ *
1812+ * This program is distributed in the hope that it will be useful,
1813+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1814+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1815+ * GNU General Public License for more details.
1816+ *
1817+ * You should have received a copy of the GNU General Public License
1818+ * along with this program; if not, write to the Free Software
1819+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1820+ */
1821+
1822+#ifndef _SOLAR_SYSTEM_EDITOR_HPP_
1823+#define _SOLAR_SYSTEM_EDITOR_HPP_
1824+
1825+#include "StelGui.hpp"
1826+#include "StelModule.hpp"
1827+//#include "CAIMainWindow.hpp"
1828+
1829+#include <QHash>
1830+#include <QList>
1831+#include <QString>
1832+#include <QVariant>
1833+
1834+class SolarSystemManagerWindow;
1835+class SolarSystem;
1836+class QSettings;
1837+
1838+//! Convenience type for storage of SSO properties in ssystem.ini format.
1839+//! This is an easy way of storing data in the format used in Stellarium's
1840+//! solar system configuration file.
1841+//! What would be key/value pairs in a section in the ssystem.ini file
1842+//! are key/value pairs in the hash. The section name is stored with key
1843+//! "section_name".
1844+//! As it is a hash, key names are not stored alphabetically. This allows
1845+//! for rapid addition and look-up of values, unlike a real QSettings
1846+//! object in StelIniFormat.
1847+//! Also, using this way may allow scripts to define SSOs.
1848+//! \todo Better name.
1849+typedef QHash<QString, QVariant> SsoElements;
1850+
1851+/*!
1852+ \class SolarSystemEditor
1853+ \brief Main class of the Solar System Editor plug-in.
1854+ \author Bogdan Marinov
1855+
1856+ Solar System bodies are identified by their names in Stellarium, but entries
1857+ in the configuration file are identified by their group (section) names.
1858+ This makes more difficult the detection of duplicates.
1859+*/
1860+class SolarSystemEditor : public StelModule
1861+{
1862+ Q_OBJECT
1863+
1864+public:
1865+ SolarSystemEditor();
1866+ virtual ~SolarSystemEditor();
1867+
1868+ ///////////////////////////////////////////////////////////////////////////
1869+ // Methods inherited from the StelModule class
1870+ //! called when the plug-in is loaded.
1871+ //! All initializations should be done here.
1872+ virtual void init();
1873+ //! called before the plug-in is un-loaded.
1874+ //! Useful for stopping processes, unloading textures, etc.
1875+ virtual void deinit();
1876+ virtual void update(double deltaTime);
1877+ //! draws on the view port.
1878+ //! Dialog windows don't need explicit drawing, it's done automatically.
1879+ //! If a plug-in draws on the screen, it should be able to respect
1880+ //! the night vision mode.
1881+ virtual void draw(StelCore * core);
1882+ virtual double getCallOrder(StelModuleActionName actionName) const;
1883+ //! called when the "configure" button in the "Plugins" tab is pressed
1884+ virtual bool configureGui(bool show);
1885+ virtual void updateI18n();
1886+
1887+ //! Reads a single comet's orbital elements from a string.
1888+ //! This function converts a line of comet orbital elements in MPC format
1889+ //! to a hash in Stellarium's ssystem.ini format.
1890+ //! The MPC's one-line orbital elements format for comets
1891+ //! is described on their website:
1892+ //! http://www.minorplanetcenter.org/iau/info/CometOrbitFormat.html
1893+ //! \returns an empty hash if there is an error or the source string is not
1894+ //! a valid line in MPC format.
1895+ //! \todo Recognise the long form packed designations (to handle fragments)
1896+ //! \todo Handle better any unusual symbols in section names (URL encoding?)
1897+ //! \todo Use column cuts intead of a regular expression?
1898+ SsoElements readMpcOneLineCometElements(QString oneLineElements);
1899+
1900+ //! Reads a single minor planet's orbital elements from a string.
1901+ //! This function converts a line of minor planet orbital elements in
1902+ //! MPC format to a hash in Stellarium's ssystem.ini format.
1903+ //! The MPC's one-line orbital elements format for minor planets
1904+ //! is described on their website:
1905+ //! http://www.minorplanetcenter.org/iau/info/MPOrbitFormat.html
1906+ //! \returns an empty hash if there is an error or the source string is not
1907+ //! a valid line in MPC format.
1908+ //! \todo Handle better any unusual symbols in section names (URL encoding?)
1909+ SsoElements readMpcOneLineMinorPlanetElements(QString oneLineElements);
1910+
1911+ //! Reads a single object's orbital elements from a string.
1912+ //! This function converts a line of orbital elements in XEphem format
1913+ //! to a hash in Stellarium's ssystem.ini format.
1914+ //! http://www.clearskyinstitute.com/xephem/help/xephem.html#mozTocId468501
1915+ //! It recognises only the 'e', 'h' and 'p' types of orbits in XEphem's
1916+ //! format (comets and minor planets). It is used in handling on-line search
1917+ //! queries to the MPC's Minor Planet and Comet Ephemeris System, as
1918+ //! using the MPC format causes long object names to be truncated
1919+ //! due to the fixed width of the columns.
1920+ //! An object's type (comet or asteroid) is determined based on its name.
1921+ SsoElements readXEphemOneLineElements(QString oneLineElements);
1922+
1923+ //! Reads a list of comet orbital elements from a file.
1924+ //! This function reads a list of comet orbital elements in MPC's one-line
1925+ //! format from a file (one comet per line) and converts it to a list of
1926+ //! hashes in Stellarium's ssystem.ini format.
1927+ //! Example source file is the list of observable comets on the MPC's site:
1928+ //! http://www.minorplanetcenter.org/iau/Ephemerides/Comets/Soft00Cmt.txt
1929+ //! readMpcOneLineCometElements() is used internally to parse each line.
1930+ QList<SsoElements> readMpcOneLineCometElementsFromFile(QString filePath);
1931+
1932+ //! Reads a list of minor planet orbital elements from a file.
1933+ //! This function reads a list of minor planets orbital elements in MPC's
1934+ //! one-line format from a file (one comet per line) and converts it to
1935+ //! a list of hashes in Stellarium's ssystem.ini format.
1936+ //! Example source file is the list of bright asteroids on the MPC's site:
1937+ //! http://www.minorplanetcenter.org/iau/Ephemerides/Bright/2010/Soft00Bright.txt
1938+ //! readMpcOneLineMinorPlanetElements() is used internally to parse each line.
1939+ QList<SsoElements> readMpcOneLineMinorPlanetElementsFromFile(QString filePath);
1940+
1941+ //! Reads a list of Solar System object orbital elements from a file.
1942+ //! This function reads a list of Solar System object orbital elements in
1943+ //! XEphem's one-line format (one object per line, comment lines starting
1944+ //! with # are skipped) and converts it to a list of hashes in Stellarium's
1945+ //! ssystem.ini format. XEphem's file format is described in its manual:
1946+ //! http://www.clearskyinstitute.com/xephem/help/xephem.html#mozTocId468501
1947+ //! Example source file can be any of the lists of objects on the MPC site:
1948+ //! http://www.minorplanetcenter.org/iau/Ephemerides/Comets/Soft03Cmt.txt
1949+ //! http://www.minorplanetcenter.org/iau/Ephemerides/Bright/2010/Soft03Bright.txt
1950+ //! readXEphemOneLineElements() is used internally to parse each line.
1951+ QList<SsoElements> readXEphemOneLineElementsFromFile(QString filePath);
1952+
1953+ //! Adds a new entry at the end of the user solar system configuration file.
1954+ //! This function writes directly to the file. See the note on why QSettings
1955+ //! was not used in the description of
1956+ //! appendToSolarSystemConfigurationFile(QList<SsoElements>)
1957+ //! Duplicates are removed: If any section in the file matches the
1958+ //! "section_name" value of the inserted entry, it is removed.
1959+ bool appendToSolarSystemConfigurationFile(SsoElements object);
1960+
1961+ //! Adds new entries at the end of the user solar system configuration file.
1962+ //! This function writes directly to the file. QSettings was not used, as:
1963+ //! - Using QSettings with QSettings::IniFormat causes the list in the
1964+ //! "color" field (e.g. "1.0, 1.0, 1.0") to be wrapped in double quotation
1965+ //! marks (Stellarium requires no quotation marks).
1966+ //! - Using QSettings with StelIniFormat causes unaccepptable append times
1967+ //! when the file grows (>~40 entries). This most probably happens because
1968+ //! StelIniParser uses QMap internally for the entry list. QMap orders its
1969+ //! keys (in the case of strings - alphabetically) and it has to find
1970+ //! the appropriate place in the ordering for every new key, which takes
1971+ //! more and more time as the list grows.
1972+ //!
1973+ //! Duplicates are removed: If any section in the file matches the
1974+ //! "section_name" value of a new entry, it is removed.
1975+ //! Invalid entries in the list (that don't contain a value for
1976+ //! "section_name" or it is an empty string) are skipped and the processing
1977+ //! continues from the next entry.
1978+ //! \todo Protect the default Solar System configuration?
1979+ //! \todo At least warn when overwriting old entries?
1980+ bool appendToSolarSystemConfigurationFile(QList<SsoElements>);
1981+
1982+ //! Flags to control the updateSolarSystemConfigurationFile() function.
1983+ enum UpdateFlag {
1984+ UpdateNameAndNumber = 0x01,//!< Update the name and minor planet number, if any.
1985+ UpdateType = 0x02, //!< Update objects that lack the "type" parameter
1986+ UpdateOrbitalElements = 0x04, //!< Update the orbital elements, including the orbit function.
1987+ UpdateMagnitudeParameters = 0x08 //!< Update the values in the two parameter system, or add them if they are missing and the type allows.
1988+ };
1989+ Q_DECLARE_FLAGS(UpdateFlags, UpdateFlag)
1990+
1991+ //! Updates entries in the user solar system configuration file.
1992+ //! \param objects a list of data for already existing objects (non-existing ones are skipped);
1993+ //! \param flags flags controlling what is being updated. See UpdateFlag.
1994+ //! \returns false if the operation has failed completely for some reason.
1995+ bool updateSolarSystemConfigurationFile(QList<SsoElements> objects, UpdateFlags flags);
1996+
1997+ //! Returns the names of the objects listed in the default ssystem.ini.
1998+ //! The default solar system configuration file is assumed to be the one
1999+ //! in the installation directory.
2000+ QHash<QString,QString> getDefaultSsoIdentifiers() {return defaultSsoIdentifiers;}
2001+
2002+ //! Lists the objects listed in the current user ssystem.ini.
2003+ //! As the name suggests, the list is compiled when the function is run.
2004+ QHash<QString,QString> listAllLoadedSsoIdentifiers();
2005+
2006+ //! Removes an object from the user Solar System configuration file.
2007+ //! Reloads the Solar System on successfull removal.
2008+ //! \arg name true name of the object ("name" parameter in the configuration file)
2009+ //! \returns true if the entry has been removed successfully or there is
2010+ //! no such entry
2011+ //! \returns false if there was an error
2012+ bool removeSsoWithName(QString name);
2013+
2014+ //!
2015+ bool copySolarSystemConfigurationFileTo(QString filePath);
2016+ //!
2017+ bool replaceSolarSystemConfigurationFileWith(QString filePath);
2018+
2019+ //! returns the path
2020+ QString getCustomSolarSystemFilePath() const {return customSolarSystemFilePath;}
2021+
2022+public slots:
2023+ //! Resets the Solar System configuration file and reloads the Solar System.
2024+ //! \todo Return a bool and make the GUI display a message if it was not successful.
2025+ void resetSolarSystemToDefault();
2026+
2027+signals:
2028+ //TODO: This should be part of SolarSystem::reloadPlanets()
2029+ void solarSystemChanged();
2030+
2031+private:
2032+ bool isInitialized;
2033+
2034+ //! Main window of the module's GUI
2035+ SolarSystemManagerWindow * mainWindow;
2036+
2037+ QSettings * solarSystemConfigurationFile;
2038+ SolarSystem * solarSystemManager;
2039+
2040+ QString customSolarSystemFilePath;
2041+ QString defaultSolarSystemFilePath;
2042+
2043+ //! A hash matching SSO names with the group names used to identify them
2044+ //! in the configuration file.
2045+
2046+ //! The names and group names of all objects in the default ssystem.ini.
2047+ //! The keys are the names, the values are the group names.
2048+ //! Initialized in init().
2049+ QHash<QString,QString> defaultSsoIdentifiers;
2050+
2051+ //! Gets the names of the objects listed in a ssystem.ini-formatted file.
2052+ //! Used internally in readAllCurrentSsoNames() and in init() to initialize
2053+ //! defaultSsoNames.
2054+ //! Does not check if the file exists.
2055+ QHash<QString,QString> listAllLoadedObjectsInFile(QString filePath);
2056+
2057+ //! Creates a copy of the default ssystem.ini file in the user data directory.
2058+ //! \returns true if a file already exists or the copying has been successful
2059+ bool cloneSolarSystemConfigurationFile();
2060+
2061+ //! Replaces the user copy of ssystem.ini with the default one.
2062+ //! This function simply deletes the file, if it exists, and calls
2063+ //! cloneSolarSystemConfigurationFile().
2064+ //! \returns true if the replacement has been successfull.
2065+ bool resetSolarSystemConfigurationFile();
2066+
2067+ //! Converts an alphanumeric digit as used in MPC packed dates to an integer.
2068+ //! See http://www.minorplanetcenter.org/iau/info/PackedDates.html
2069+ //! Interprets the digits from 1 to 9 normally, and the capital leters
2070+ //! from A to V as numbers between 10 and 31.
2071+ //! \returns 0 if the digit is invalid (0 is also an invalid ordinal number
2072+ //! for a day or month, so this is not a problem)
2073+ int unpackDayOrMonthNumber (QChar digit);
2074+ //! Converts an alphanumeric year number as used in MPC packed dates to an integer.
2075+ //! See http://www.minorplanetcenter.org/iau/info/PackedDates.html
2076+ //! Also used in packed provisional designations, see
2077+ //! http://www.minorplanetcenter.org/iau/info/PackedDes.html
2078+ int unpackYearNumber (QChar prefix, int lastTwoDigits);
2079+ //! Converts a two-character number used in MPC packed provisional designations.
2080+ //! See http://www.minorplanetcenter.org/iau/info/PackedDes.html
2081+ //! This function is used for both asteroid and comet designations.
2082+ int unpackAlphanumericNumber (QChar prefix, int lastDigit);
2083+
2084+ //TODO: This should be public and static, perhaps?
2085+ //! Unpacks an MPC packed minor planet provisional designation.
2086+ //! See http://www.minorplanetcenter.org/iau/info/PackedDes.html
2087+ //! \returns an empty string if the argument is not a valid packed
2088+ //! provisional designation.
2089+ QString unpackMinorPlanetProvisionalDesignation(QString packedDesignation);
2090+
2091+ //! Updates a value in a configuration file with a value with the same key in a SsoElements hash.
2092+ void updateSsoProperty(QSettings& configuration, SsoElements& properties, QString key);
2093+
2094+ //! Converts an object name to a key (group) name in a configuration file.
2095+ QString convertToGroupName(QString& name, int minorPlanetNumber = 0);
2096+};
2097+
2098+
2099+#include "fixx11h.h"
2100+#include <QObject>
2101+#include "StelPluginInterface.hpp"
2102+
2103+//! This class is used by Qt to manage a plug-in interface
2104+class SolarSystemEditorStelPluginInterface : public QObject, public StelPluginInterface
2105+{
2106+ Q_OBJECT
2107+ Q_INTERFACES(StelPluginInterface)
2108+public:
2109+ virtual StelModule* getStelModule() const;
2110+ virtual StelPluginInfo getPluginInfo() const;
2111+};
2112+
2113+#endif //_SOLAR_SYSTEM_EDITOR_HPP_
2114
2115=== added directory 'plugins/SolarSystemEditor/src/gui'
2116=== added file 'plugins/SolarSystemEditor/src/gui/MPCImporterDialogPrototype02.ui'
2117--- plugins/SolarSystemEditor/src/gui/MPCImporterDialogPrototype02.ui 1970-01-01 00:00:00 +0000
2118+++ plugins/SolarSystemEditor/src/gui/MPCImporterDialogPrototype02.ui 2010-11-16 20:06:17 +0000
2119@@ -0,0 +1,171 @@
2120+<?xml version="1.0" encoding="UTF-8"?>
2121+<ui version="4.0">
2122+ <author>Bogdan Marinov</author>
2123+ <class>Form</class>
2124+ <widget class="QWidget" name="Form">
2125+ <property name="geometry">
2126+ <rect>
2127+ <x>0</x>
2128+ <y>0</y>
2129+ <width>400</width>
2130+ <height>300</height>
2131+ </rect>
2132+ </property>
2133+ <layout class="QVBoxLayout" name="verticalLayout_5">
2134+ <property name="spacing">
2135+ <number>0</number>
2136+ </property>
2137+ <property name="margin">
2138+ <number>0</number>
2139+ </property>
2140+ <item>
2141+ <widget class="QStackedWidget" name="stackedWidget">
2142+ <property name="currentIndex">
2143+ <number>0</number>
2144+ </property>
2145+ <widget class="QWidget" name="page">
2146+ <layout class="QVBoxLayout" name="verticalLayout">
2147+ <property name="spacing">
2148+ <number>0</number>
2149+ </property>
2150+ <property name="margin">
2151+ <number>0</number>
2152+ </property>
2153+ <item>
2154+ <widget class="QGroupBox" name="groupBox">
2155+ <property name="title">
2156+ <string>Select source</string>
2157+ </property>
2158+ <layout class="QVBoxLayout" name="verticalLayout_2">
2159+ <item>
2160+ <widget class="QRadioButton" name="radioButton">
2161+ <property name="text">
2162+ <string>Import a single line (one body)</string>
2163+ </property>
2164+ </widget>
2165+ </item>
2166+ <item>
2167+ <layout class="QHBoxLayout" name="horizontalLayout">
2168+ <item>
2169+ <widget class="QLineEdit" name="lineEdit"/>
2170+ </item>
2171+ <item>
2172+ <widget class="QPushButton" name="pushButton_3">
2173+ <property name="text">
2174+ <string>Paste</string>
2175+ </property>
2176+ </widget>
2177+ </item>
2178+ </layout>
2179+ </item>
2180+ <item>
2181+ <widget class="QRadioButton" name="radioButton_2">
2182+ <property name="text">
2183+ <string>Import bodies from a file</string>
2184+ </property>
2185+ </widget>
2186+ </item>
2187+ <item>
2188+ <layout class="QHBoxLayout" name="horizontalLayout_2">
2189+ <item>
2190+ <widget class="QLineEdit" name="lineEdit_2"/>
2191+ </item>
2192+ <item>
2193+ <widget class="QPushButton" name="pushButton_4">
2194+ <property name="text">
2195+ <string>Browse</string>
2196+ </property>
2197+ </widget>
2198+ </item>
2199+ </layout>
2200+ </item>
2201+ <item>
2202+ <spacer name="verticalSpacer">
2203+ <property name="orientation">
2204+ <enum>Qt::Vertical</enum>
2205+ </property>
2206+ <property name="sizeHint" stdset="0">
2207+ <size>
2208+ <width>20</width>
2209+ <height>40</height>
2210+ </size>
2211+ </property>
2212+ </spacer>
2213+ </item>
2214+ </layout>
2215+ </widget>
2216+ </item>
2217+ </layout>
2218+ </widget>
2219+ <widget class="QWidget" name="page_2">
2220+ <layout class="QVBoxLayout" name="verticalLayout_3">
2221+ <property name="spacing">
2222+ <number>0</number>
2223+ </property>
2224+ <property name="margin">
2225+ <number>0</number>
2226+ </property>
2227+ <item>
2228+ <widget class="QGroupBox" name="groupBox_2">
2229+ <property name="title">
2230+ <string>Objects found</string>
2231+ </property>
2232+ <layout class="QVBoxLayout" name="verticalLayout_4">
2233+ <item>
2234+ <widget class="QLabel" name="label">
2235+ <property name="text">
2236+ <string>Mark the objects you wish to be imported.</string>
2237+ </property>
2238+ </widget>
2239+ </item>
2240+ <item>
2241+ <widget class="QListWidget" name="listWidget">
2242+ <item>
2243+ <property name="text">
2244+ <string notr="true">2P/Encke</string>
2245+ </property>
2246+ <property name="checkState">
2247+ <enum>Unchecked</enum>
2248+ </property>
2249+ <property name="flags">
2250+ <set>ItemIsSelectable|ItemIsUserCheckable|ItemIsEnabled</set>
2251+ </property>
2252+ </item>
2253+ </widget>
2254+ </item>
2255+ </layout>
2256+ </widget>
2257+ </item>
2258+ </layout>
2259+ </widget>
2260+ </widget>
2261+ </item>
2262+ <item>
2263+ <layout class="QHBoxLayout" name="horizontalLayout_3">
2264+ <property name="leftMargin">
2265+ <number>10</number>
2266+ </property>
2267+ <property name="rightMargin">
2268+ <number>10</number>
2269+ </property>
2270+ <item>
2271+ <widget class="QPushButton" name="pushButton">
2272+ <property name="text">
2273+ <string>Next</string>
2274+ </property>
2275+ </widget>
2276+ </item>
2277+ <item>
2278+ <widget class="QPushButton" name="pushButton_2">
2279+ <property name="text">
2280+ <string>Cancel</string>
2281+ </property>
2282+ </widget>
2283+ </item>
2284+ </layout>
2285+ </item>
2286+ </layout>
2287+ </widget>
2288+ <resources/>
2289+ <connections/>
2290+</ui>
2291
2292=== added file 'plugins/SolarSystemEditor/src/gui/ManualImportWindow.cpp'
2293--- plugins/SolarSystemEditor/src/gui/ManualImportWindow.cpp 1970-01-01 00:00:00 +0000
2294+++ plugins/SolarSystemEditor/src/gui/ManualImportWindow.cpp 2010-11-16 20:06:17 +0000
2295@@ -0,0 +1,257 @@
2296+/*
2297+ * Solar System editor plug-in for Stellarium
2298+ *
2299+ * Copyright (C) 2010 Bogdan Marinov
2300+ *
2301+ * This program is free software; you can redistribute it and/or
2302+ * modify it under the terms of the GNU General Public License
2303+ * as published by the Free Software Foundation; either version 2
2304+ * of the License, or (at your option) any later version.
2305+ *
2306+ * This program is distributed in the hope that it will be useful,
2307+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2308+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2309+ * GNU General Public License for more details.
2310+ *
2311+ * You should have received a copy of the GNU General Public License
2312+ * along with this program; if not, write to the Free Software
2313+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2314+ */
2315+
2316+#include "SolarSystemEditor.hpp"
2317+
2318+#include "ManualImportWindow.hpp"
2319+#include "ui_manualImportWindow.h"
2320+
2321+#include <QColor>
2322+#include <QColorDialog>
2323+#include <QFileDialog>
2324+#include <QImageReader>
2325+
2326+#include "StelApp.hpp"
2327+#include "StelFileMgr.hpp"
2328+#include "StelModuleMgr.hpp"
2329+
2330+
2331+ManualImportWindow::ManualImportWindow()
2332+{
2333+ ui = new Ui_manualImportWindow();
2334+ ssoManager = GETSTELMODULE(SolarSystemEditor);
2335+}
2336+
2337+ManualImportWindow::~ManualImportWindow()
2338+{
2339+ delete ui;
2340+}
2341+
2342+void ManualImportWindow::createDialogContent()
2343+{
2344+ ui->setupUi(dialog);
2345+
2346+ //Signals
2347+ connect(ui->closeStelWindow, SIGNAL(clicked()), this, SLOT(close()));
2348+
2349+ connect(ui->lineEditColor, SIGNAL(textChanged(QString)), this, SLOT(parseColorString(QString)));
2350+ connect(ui->pushButtonSelectColor, SIGNAL(clicked()), this, SLOT(selectColor()));
2351+
2352+ connect(ui->pushButtonSelectTexture, SIGNAL(clicked()), this, SLOT(selectPlanetTextureFile()));
2353+ connect(ui->pushButtonSelectRingTexture, SIGNAL(clicked()), this, SLOT(selectRingTextureFile()));
2354+
2355+ ui->labelLongitudeOfTheAscendingNode->setText(QString("Longitude of the ascending node %1:").arg(QChar(0x03A9)));//Capital omega
2356+ ui->radioButtonArgumentOfPeriapsis->setText(QString("Argument of periapsis %1:").arg(QChar(0x3C9)));//Lowercase omega
2357+ ui->radioButtonLongitudeOfPeriapsis->setText(QString("Longitude of periapsis %1:").arg(QChar(0x3D6)));
2358+
2359+ //TODO: Move to "set defaults" function
2360+ ui->lineEditColor->setText("1.0, 1.0, 1.0");
2361+ ui->lineEditTexture->setText("nomap.png");
2362+ ui->lineEditRingTexture->setText("saturn_rings_radial.png");
2363+}
2364+
2365+void ManualImportWindow::languageChanged()
2366+{
2367+ if (dialog)
2368+ ui->retranslateUi(dialog);
2369+}
2370+
2371+void ManualImportWindow::selectColor()
2372+{
2373+ QColor color = QColorDialog::getColor(objectColor);
2374+ objectColor = color;
2375+ ui->lineEditColor->setText(QString("%1, %2, %3").arg(color.redF()).arg(color.greenF()).arg(color.blueF()));
2376+ setColorButtonColor(color);
2377+}
2378+
2379+void ManualImportWindow::parseColorString(QString colorCode)
2380+{
2381+ QStringList colorComponents = colorCode.split(QChar(','));
2382+ int count = colorComponents.count();
2383+ if (count < 3 || count > 4)
2384+ return;
2385+
2386+ bool ok;
2387+ double red = colorComponents.at(0).toDouble(&ok);
2388+ if (!ok || red < 0.0 || red > 1.0)
2389+ return;
2390+ double green = colorComponents.at(1).toDouble(&ok);
2391+ if (!ok || green < 0.0 || green > 1.0)
2392+ return;
2393+ double blue = colorComponents.at(2).toDouble(&ok);
2394+ if (!ok || blue < 0.0 || blue > 1.0)
2395+ return;
2396+
2397+ QColor color;
2398+ color.setRedF(red);
2399+ color.setGreenF(green);
2400+ color.setBlueF(blue);
2401+
2402+ if (count == 4)
2403+ {
2404+ double alpha = colorComponents.at(3).toDouble(&ok);
2405+ if (!ok || alpha < 0.0 || alpha > 1.0)
2406+ return;
2407+ color.setAlphaF(alpha);
2408+ }
2409+
2410+ objectColor = color;
2411+ setColorButtonColor(color);
2412+}
2413+
2414+void ManualImportWindow::setColorButtonColor(QColor newColor)
2415+{
2416+ qDebug() << "setColorButtonColor()";
2417+ QPixmap pixmap(16, 16);
2418+ pixmap.fill(newColor);
2419+ ui->pushButtonSelectColor->setIcon(QIcon(pixmap));
2420+}
2421+
2422+void ManualImportWindow::toggleCometOrbit(bool)
2423+{
2424+ //
2425+}
2426+
2427+void ManualImportWindow::toggleEllipticOrbit(bool)
2428+{
2429+ //
2430+}
2431+
2432+void ManualImportWindow::toggleObjectSpecificOrbit(bool)
2433+{
2434+ //
2435+}
2436+
2437+void ManualImportWindow::toggleMeanMotionOrPeriod(bool)
2438+{
2439+ //
2440+}
2441+
2442+void ManualImportWindow::selectPlanetTextureFile()
2443+{
2444+ selectTextureFile(ui->lineEditTexture);
2445+}
2446+
2447+void ManualImportWindow::selectRingTextureFile()
2448+{
2449+ selectTextureFile(ui->lineEditRingTexture);
2450+}
2451+
2452+void ManualImportWindow::selectTextureFile(QLineEdit * filePathLineEdit)
2453+{
2454+ //Find out the parent directory of the last selected file.
2455+ //Open the textures directory if no file have been selected.
2456+ QString texturesDirectoryPath;
2457+ QString currentFileName = filePathLineEdit->text();
2458+ if (currentFileName.isEmpty())
2459+ {
2460+ try
2461+ {
2462+ texturesDirectoryPath = StelFileMgr::findFile("textures", StelFileMgr::Directory);
2463+ }
2464+ catch (std::runtime_error &e)
2465+ {
2466+ qDebug() << e.what();
2467+ return;
2468+ }
2469+ }
2470+ else
2471+ {
2472+ QString currentFilePath;
2473+ try
2474+ {
2475+ currentFilePath = StelFileMgr::findFile("textures/" + currentFileName, StelFileMgr::File);
2476+ }
2477+ catch (std::runtime_error &e)
2478+ {
2479+ qDebug() << e.what();
2480+ filePathLineEdit->clear();
2481+ return;
2482+ }
2483+ if (currentFilePath.isEmpty())
2484+ {
2485+ filePathLineEdit->clear();
2486+ return;
2487+ }
2488+ QFileInfo currentFileInfo(currentFilePath);
2489+ texturesDirectoryPath = currentFileInfo.canonicalPath();
2490+ }
2491+
2492+ //Select an existing file
2493+ QStringList supportedFormats;
2494+ foreach (QByteArray format, QImageReader::supportedImageFormats())
2495+ {
2496+ supportedFormats.append(QString("*.%1").arg(QString(format)));//It's a wee bit long...
2497+ }
2498+ QString fileFilter = QString("Texture files (%1)").arg(supportedFormats.join(" "));
2499+ QString newFilePath = QFileDialog::getOpenFileName(0, QString(), texturesDirectoryPath, fileFilter);
2500+
2501+ //Is the file in one of the two "textures" directories?
2502+ if (newFilePath.isEmpty())
2503+ return;
2504+ QFileInfo newFileInfo(newFilePath);
2505+ QDir newFileParentDirectory = newFileInfo.dir();
2506+ if (newFileParentDirectory.dirName() != "textures")
2507+ return;
2508+ QDir installedTexturesDirectory(StelFileMgr::getInstallationDir() + "/textures");
2509+ QDir userTexturesDirectory(StelFileMgr::getUserDir() + "/textures");
2510+ if (newFileParentDirectory != installedTexturesDirectory && newFileParentDirectory != userTexturesDirectory)
2511+ return;
2512+
2513+ if (verifyTextureFile(newFileInfo.canonicalFilePath()))
2514+ filePathLineEdit->setText(newFileInfo.fileName());
2515+}
2516+
2517+bool ManualImportWindow::verifyTextureFile(QString filePath)
2518+{
2519+ //TODO: Absolute path? File exists?
2520+
2521+ QPixmap texture(filePath);
2522+
2523+ if (texture.isNull())
2524+ {
2525+ qDebug() << "File doesn't exist or is not an accepted texure format:"
2526+ << filePath;
2527+ return false;
2528+ }
2529+
2530+ if (!verifyPowerOfTwo(texture.height()))
2531+ {
2532+ qDebug() << "Invalid texure height:" << texture.height()
2533+ << "for file" << filePath;
2534+ return false;
2535+ }
2536+ if (!verifyPowerOfTwo(texture.width()))
2537+ {
2538+ qDebug() << "Invalid texture width:" << texture.width()
2539+ << "for file" << filePath;
2540+ return false;
2541+ }
2542+
2543+ return true;
2544+}
2545+
2546+bool ManualImportWindow::verifyPowerOfTwo(int value)
2547+{
2548+ if (value > 0 && (value & (value-1)) == 0)
2549+ return true;
2550+ else
2551+ return false;
2552+}
2553
2554=== added file 'plugins/SolarSystemEditor/src/gui/ManualImportWindow.hpp'
2555--- plugins/SolarSystemEditor/src/gui/ManualImportWindow.hpp 1970-01-01 00:00:00 +0000
2556+++ plugins/SolarSystemEditor/src/gui/ManualImportWindow.hpp 2010-11-16 20:06:17 +0000
2557@@ -0,0 +1,79 @@
2558+/*
2559+ * Solar System editor plug-in for Stellarium
2560+ *
2561+ * Copyright (C) 2010 Bogdan Marinov
2562+ *
2563+ * This program is free software; you can redistribute it and/or
2564+ * modify it under the terms of the GNU General Public License
2565+ * as published by the Free Software Foundation; either version 2
2566+ * of the License, or (at your option) any later version.
2567+ *
2568+ * This program is distributed in the hope that it will be useful,
2569+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2570+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2571+ * GNU General Public License for more details.
2572+ *
2573+ * You should have received a copy of the GNU General Public License
2574+ * along with this program; if not, write to the Free Software
2575+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2576+ */
2577+
2578+#ifndef _MANUAL_IMPORT_WINDOW_
2579+#define _MANUAL_IMPORT_WINDOW_
2580+
2581+#include <QObject>
2582+#include "StelDialog.hpp"
2583+
2584+#include "SolarSystemEditor.hpp"
2585+
2586+#include <QColor>
2587+
2588+class Ui_manualImportWindow;
2589+class QLineEdit;
2590+
2591+/*! \brief Window for manual entry of Solar System object properties.
2592+ \author Bogdan Marinov
2593+*/
2594+class ManualImportWindow : public StelDialog
2595+{
2596+ Q_OBJECT
2597+public:
2598+ ManualImportWindow();
2599+ virtual ~ManualImportWindow();
2600+ void languageChanged();
2601+
2602+private slots:
2603+ //TODO: Object type
2604+
2605+ void selectColor();
2606+ void parseColorString(QString);
2607+
2608+ void toggleCometOrbit(bool);
2609+ void toggleEllipticOrbit(bool);
2610+ void toggleObjectSpecificOrbit(bool);
2611+
2612+ void toggleMeanMotionOrPeriod(bool);
2613+
2614+ void selectPlanetTextureFile();
2615+ void selectRingTextureFile();
2616+ //TODO: Parse input in the line edits? (Otherwise, leave them read-only.)
2617+
2618+private:
2619+ SolarSystemEditor * ssoManager;
2620+
2621+ QColor objectColor;
2622+
2623+ void setColorButtonColor(QColor newColor);
2624+
2625+ void selectTextureFile(QLineEdit * filePathLineEdit);
2626+ //! Check if a file is a valid graphics file with OpenGL texture dimensions.
2627+ //! OpenGL accepts only dimentions that are powers of 2 (512, 1024, etc.)
2628+ bool verifyTextureFile(QString filePath);
2629+ bool verifyPowerOfTwo(int value);
2630+
2631+protected:
2632+ virtual void createDialogContent();
2633+ Ui_manualImportWindow * ui;
2634+};
2635+
2636+#endif //_MANUAL_IMPORT_WINDOW_
2637
2638=== added file 'plugins/SolarSystemEditor/src/gui/MpcImportWindow.cpp'
2639--- plugins/SolarSystemEditor/src/gui/MpcImportWindow.cpp 1970-01-01 00:00:00 +0000
2640+++ plugins/SolarSystemEditor/src/gui/MpcImportWindow.cpp 2010-11-16 20:06:17 +0000
2641@@ -0,0 +1,958 @@
2642+/*
2643+ * Solar System editor plug-in for Stellarium
2644+ *
2645+ * Copyright (C) 2010 Bogdan Marinov
2646+ *
2647+ * This program is free software; you can redistribute it and/or
2648+ * modify it under the terms of the GNU General Public License
2649+ * as published by the Free Software Foundation; either version 2
2650+ * of the License, or (at your option) any later version.
2651+ *
2652+ * This program is distributed in the hope that it will be useful,
2653+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2654+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2655+ * GNU General Public License for more details.
2656+ *
2657+ * You should have received a copy of the GNU General Public License
2658+ * along with this program; if not, write to the Free Software
2659+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2660+ */
2661+
2662+#include "SolarSystemEditor.hpp"
2663+
2664+#include "MpcImportWindow.hpp"
2665+#include "ui_mpcImportWindow.h"
2666+
2667+#include "StelApp.hpp"
2668+#include "StelFileMgr.hpp"
2669+#include "StelJsonParser.hpp"
2670+#include "StelModuleMgr.hpp"
2671+#include "SolarSystem.hpp"
2672+
2673+#include <QApplication>
2674+#include <QClipboard>
2675+#include <QFileDialog>
2676+#include <QHash>
2677+#include <QList>
2678+#include <QNetworkAccessManager>
2679+#include <QNetworkRequest>
2680+#include <QNetworkReply>
2681+#include <QString>
2682+#include <QTemporaryFile>
2683+#include <QTimer>
2684+#include <QUrl>
2685+
2686+MpcImportWindow::MpcImportWindow()
2687+{
2688+ ui = new Ui_mpcImportWindow();
2689+ ssoManager = GETSTELMODULE(SolarSystemEditor);
2690+
2691+ networkManager = StelApp::getInstance().getNetworkAccessManager();
2692+
2693+ downloadReply = NULL;
2694+ queryReply = NULL;
2695+ downloadProgressBar = NULL;
2696+ queryProgressBar = NULL;
2697+
2698+ countdownTimer = new QTimer(this);
2699+
2700+ QHash<QString,QString> asteroidBookmarks;
2701+ QHash<QString,QString> cometBookmarks;
2702+ bookmarks.insert(MpcComets, cometBookmarks);
2703+ bookmarks.insert(MpcMinorPlanets, asteroidBookmarks);
2704+}
2705+
2706+MpcImportWindow::~MpcImportWindow()
2707+{
2708+ delete ui;
2709+ delete countdownTimer;
2710+ if (downloadReply)
2711+ downloadReply->deleteLater();
2712+ if (queryReply)
2713+ queryReply->deleteLater();
2714+ if (downloadProgressBar)
2715+ downloadProgressBar->deleteLater();
2716+ if (queryProgressBar)
2717+ queryProgressBar->deleteLater();
2718+}
2719+
2720+void MpcImportWindow::createDialogContent()
2721+{
2722+ ui->setupUi(dialog);
2723+
2724+ //Signals
2725+ connect(ui->closeStelWindow, SIGNAL(clicked()), this, SLOT(close()));
2726+
2727+ connect(ui->pushButtonAcquire, SIGNAL(clicked()), this, SLOT(acquireObjectData()));
2728+ connect(ui->pushButtonAbortDownload, SIGNAL(clicked()), this, SLOT(abortDownload()));
2729+ connect(ui->pushButtonAdd, SIGNAL(clicked()), this, SLOT(addObjects()));
2730+ connect(ui->pushButtonDiscard, SIGNAL(clicked()), this, SLOT(discardObjects()));
2731+
2732+ connect(ui->pushButtonBrowse, SIGNAL(clicked()), this, SLOT(selectFile()));
2733+ connect(ui->pushButtonPasteURL, SIGNAL(clicked()), this, SLOT(pasteClipboardURL()));
2734+ connect(ui->comboBoxBookmarks, SIGNAL(currentIndexChanged(QString)), this, SLOT(bookmarkSelected(QString)));
2735+
2736+ //connect(ui->radioButtonSingle, SIGNAL(toggled(bool)), ui->frameSingle, SLOT(setVisible(bool)));
2737+ connect(ui->radioButtonFile, SIGNAL(toggled(bool)), ui->frameFile, SLOT(setVisible(bool)));
2738+ connect(ui->radioButtonURL, SIGNAL(toggled(bool)), ui->frameURL, SLOT(setVisible(bool)));
2739+
2740+ connect(ui->radioButtonAsteroids, SIGNAL(toggled(bool)), this, SLOT(switchImportType(bool)));
2741+ connect(ui->radioButtonComets, SIGNAL(toggled(bool)), this, SLOT(switchImportType(bool)));
2742+
2743+ connect(ui->pushButtonMarkAll, SIGNAL(clicked()), this, SLOT(markAll()));
2744+ connect(ui->pushButtonMarkNone, SIGNAL(clicked()), this, SLOT(unmarkAll()));
2745+
2746+ connect(ui->pushButtonSendQuery, SIGNAL(clicked()), this, SLOT(sendQuery()));
2747+ connect(ui->pushButtonAbortQuery, SIGNAL(clicked()), this, SLOT(abortQuery()));
2748+ connect(ui->lineEditQuery, SIGNAL(textEdited(QString)), this, SLOT(resetNotFound()));
2749+ //connect(ui->lineEditQuery, SIGNAL(editingFinished()), this, SLOT(sendQuery()));
2750+ connect(countdownTimer, SIGNAL(timeout()), this, SLOT(updateCountdown()));
2751+
2752+ loadBookmarks();
2753+
2754+ resetCountdown();
2755+ resetDialog();
2756+}
2757+
2758+void MpcImportWindow::resetDialog()
2759+{
2760+ ui->stackedWidget->setCurrentIndex(0);
2761+
2762+ //ui->tabWidget->setCurrentIndex(0);
2763+ ui->groupBoxType->setVisible(true);
2764+ ui->radioButtonAsteroids->setChecked(true);
2765+
2766+ ui->radioButtonFile->setChecked(true);
2767+ ui->frameURL->setVisible(false);
2768+
2769+ ui->lineEditFilePath->clear();
2770+ ui->lineEditQuery->clear();
2771+ ui->lineEditURL->setText("http://");
2772+ ui->checkBoxAddBookmark->setChecked(false);
2773+ ui->frameBookmarkTitle->setVisible(false);
2774+ ui->comboBoxBookmarks->setCurrentIndex(0);
2775+
2776+ ui->radioButtonUpdate->setChecked(true);
2777+ ui->checkBoxOnlyOrbitalElements->setChecked(true);
2778+
2779+ //TODO: Is this the right place?
2780+ ui->pushButtonAbortQuery->setVisible(false);
2781+ ui->pushButtonAbortDownload->setVisible(false);
2782+
2783+ //Resetting the dialog should not reset the timer
2784+ //resetCountdown();
2785+ resetNotFound();
2786+ enableInterface(true);
2787+}
2788+
2789+void MpcImportWindow::populateBookmarksList()
2790+{
2791+ ui->comboBoxBookmarks->clear();
2792+ ui->comboBoxBookmarks->addItem("Select bookmark...");
2793+ QStringList bookmarkTitles(bookmarks.value(importType).keys());
2794+ bookmarkTitles.sort();
2795+ ui->comboBoxBookmarks->addItems(bookmarkTitles);
2796+}
2797+
2798+void MpcImportWindow::languageChanged()
2799+{
2800+ if (dialog)
2801+ ui->retranslateUi(dialog);
2802+}
2803+
2804+void MpcImportWindow::acquireObjectData()
2805+{
2806+ if (ui->radioButtonFile->isChecked())
2807+ {
2808+ QString filePath = ui->lineEditFilePath->text();
2809+ if (filePath.isEmpty())
2810+ return;
2811+
2812+ QList<SsoElements> objects = readElementsFromFile(importType, filePath);
2813+ if (objects.isEmpty())
2814+ return;
2815+
2816+ //Temporary, until the slot/socket mechanism is ready
2817+ populateCandidateObjects(objects);
2818+ ui->stackedWidget->setCurrentIndex(1);
2819+ }
2820+ else if (ui->radioButtonURL->isChecked())
2821+ {
2822+ QString url = ui->lineEditURL->text();
2823+ if (url.isEmpty())
2824+ return;
2825+ startDownload(url);
2826+ }
2827+ //close();
2828+}
2829+
2830+void MpcImportWindow::addObjects()
2831+{
2832+ disconnect(ssoManager, SIGNAL(solarSystemChanged()), this, SLOT(resetDialog()));
2833+
2834+ QList<QString> checkedObjectsNames;
2835+
2836+ //Extract the marked objects
2837+ while (ui->listWidgetObjects->count() > 0)
2838+ {
2839+ QListWidgetItem * item = ui->listWidgetObjects->takeItem(0);
2840+ if (item->checkState() == Qt::Checked)
2841+ {
2842+ checkedObjectsNames.append(item->text());
2843+ }
2844+ delete item;
2845+ }
2846+ //qDebug() << "Checked:" << checkedObjectsNames;
2847+
2848+ QList<SsoElements> approvedForAddition;
2849+ for (int i = 0; i < candidatesForAddition.count(); i++)
2850+ {
2851+ QString name = candidatesForAddition.at(i).value("name").toString();
2852+ if (checkedObjectsNames.contains(name))
2853+ approvedForAddition.append(candidatesForAddition.at(i));
2854+ }
2855+
2856+ bool overwrite = ui->radioButtonOverwrite->isChecked();
2857+ QList<SsoElements> approvedForUpdate;
2858+ for (int j = 0; j < candidatesForUpdate.count(); j++)
2859+ {
2860+ QString name = candidatesForUpdate.at(j).value("name").toString();
2861+ if (checkedObjectsNames.contains(name))
2862+ {
2863+ if (overwrite)
2864+ {
2865+ approvedForAddition.append(candidatesForUpdate.at(j));
2866+ }
2867+ else
2868+ {
2869+ approvedForUpdate.append(candidatesForUpdate.at(j));
2870+ }
2871+ }
2872+ }
2873+
2874+ //Write to file
2875+ ssoManager->appendToSolarSystemConfigurationFile(approvedForAddition);
2876+
2877+ if (ui->radioButtonUpdate->isChecked())
2878+ {
2879+ SolarSystemEditor::UpdateFlags flags(SolarSystemEditor::UpdateNameAndNumber | SolarSystemEditor::UpdateOrbitalElements);
2880+ if (!ui->checkBoxOnlyOrbitalElements->isChecked())
2881+ {
2882+ flags |= SolarSystemEditor::UpdateType;
2883+ flags |= SolarSystemEditor::UpdateMagnitudeParameters;
2884+ }
2885+
2886+ ssoManager->updateSolarSystemConfigurationFile(approvedForUpdate, flags);
2887+ }
2888+
2889+ //Refresh the Solar System
2890+ GETSTELMODULE(SolarSystem)->reloadPlanets();
2891+
2892+ resetDialog();
2893+ emit objectsImported();
2894+}
2895+
2896+void MpcImportWindow::discardObjects()
2897+{
2898+ resetDialog();
2899+}
2900+
2901+void MpcImportWindow::pasteClipboardURL()
2902+{
2903+ ui->lineEditURL->setText(QApplication::clipboard()->text());
2904+}
2905+
2906+void MpcImportWindow::selectFile()
2907+{
2908+ QString filePath = QFileDialog::getOpenFileName(NULL, "Select a text file", StelFileMgr::getDesktopDir());
2909+ ui->lineEditFilePath->setText(filePath);
2910+}
2911+
2912+void MpcImportWindow::bookmarkSelected(QString bookmarkTitle)
2913+{
2914+ if (bookmarkTitle.isEmpty() || bookmarkTitle == "Select bookmark...")
2915+ {
2916+ ui->lineEditURL->clear();
2917+ return;
2918+ }
2919+ QString bookmarkUrl = bookmarks.value(importType).value(bookmarkTitle);
2920+ ui->lineEditURL->setText(bookmarkUrl);
2921+}
2922+
2923+void MpcImportWindow::populateCandidateObjects(QList<SsoElements> objects)
2924+{
2925+ candidatesForAddition.clear();
2926+
2927+ //Get a list of the current objects
2928+ QHash<QString,QString> defaultSsoIdentifiers = ssoManager->getDefaultSsoIdentifiers();
2929+ QHash<QString,QString> loadedSsoIdentifiers = ssoManager->listAllLoadedSsoIdentifiers();
2930+
2931+ //Separating the objects into visual groups in the list
2932+ int newDefaultSsoIndex = 0;
2933+ int newLoadedSsoIndex = 0;
2934+ int newNovelSsoIndex = 0;
2935+ int insertionIndex = 0;
2936+
2937+ QListWidget * list = ui->listWidgetObjects;
2938+ list->clear();
2939+ foreach (SsoElements object, objects)
2940+ {
2941+ QString name = object.value("name").toString();
2942+ if (name.isEmpty())
2943+ continue;
2944+
2945+ QString group = object.value("section_name").toString();
2946+ if (group.isEmpty())
2947+ continue;
2948+
2949+ //Prevent name conflicts between asteroids and moons
2950+ if (loadedSsoIdentifiers.contains(name))
2951+ {
2952+ if (loadedSsoIdentifiers.value(name) != group)
2953+ {
2954+ name.append('*');
2955+ object.insert("name", name);
2956+ }
2957+ }
2958+
2959+ QListWidgetItem * item = new QListWidgetItem();
2960+ item->setText(name);
2961+ item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
2962+ item->setCheckState(Qt::Unchecked);
2963+
2964+ if (defaultSsoIdentifiers.contains(name))
2965+ {
2966+ //Duplicate of a default solar system object
2967+ QFont itemFont(item->font());
2968+ itemFont.setBold(true);
2969+ item->setFont(itemFont);
2970+
2971+ candidatesForUpdate.append(object);
2972+
2973+ insertionIndex = newDefaultSsoIndex;
2974+ newDefaultSsoIndex++;
2975+ newLoadedSsoIndex++;
2976+ newNovelSsoIndex++;
2977+ }
2978+ else if (loadedSsoIdentifiers.contains(name))
2979+ {
2980+ //Duplicate of another existing object
2981+ QFont itemFont(item->font());
2982+ itemFont.setItalic(true);
2983+ item->setFont(itemFont);
2984+
2985+ candidatesForUpdate.append(object);
2986+
2987+ insertionIndex = newLoadedSsoIndex;
2988+ newLoadedSsoIndex++;
2989+ newNovelSsoIndex++;
2990+ }
2991+ else
2992+ {
2993+ candidatesForAddition.append(object);
2994+
2995+ insertionIndex = newNovelSsoIndex;
2996+ newNovelSsoIndex++;
2997+ }
2998+
2999+ list->insertItem(insertionIndex, item);
3000+ }
3001+
3002+ //Select the first item
3003+ if (list->count() > 0)
3004+ list->setCurrentRow(0);
3005+}
3006+
3007+void MpcImportWindow::enableInterface(bool enable)
3008+{
3009+ ui->groupBoxType->setVisible(enable);
3010+
3011+ ui->frameFile->setEnabled(enable);
3012+ ui->frameURL->setEnabled(enable);
3013+
3014+ ui->radioButtonFile->setEnabled(enable);
3015+ ui->radioButtonURL->setEnabled(enable);
3016+
3017+ ui->pushButtonAcquire->setEnabled(enable);
3018+}
3019+
3020+SsoElements MpcImportWindow::readElementsFromString (QString elements)
3021+{
3022+ Q_ASSERT(ssoManager);
3023+
3024+ switch (importType)
3025+ {
3026+ case MpcComets:
3027+ return ssoManager->readMpcOneLineCometElements(elements);
3028+ case MpcMinorPlanets:
3029+ default:
3030+ return ssoManager->readMpcOneLineMinorPlanetElements(elements);
3031+ }
3032+}
3033+
3034+QList<SsoElements> MpcImportWindow::readElementsFromFile(ImportType type, QString filePath)
3035+{
3036+ Q_ASSERT(ssoManager);
3037+
3038+ switch (type)
3039+ {
3040+ case MpcComets:
3041+ return ssoManager->readMpcOneLineCometElementsFromFile(filePath);
3042+ case MpcMinorPlanets:
3043+ default:
3044+ return ssoManager->readMpcOneLineMinorPlanetElementsFromFile(filePath);
3045+ }
3046+}
3047+
3048+void MpcImportWindow::switchImportType(bool)
3049+{
3050+ if (ui->radioButtonAsteroids->isChecked())
3051+ {
3052+ importType = MpcMinorPlanets;
3053+ }
3054+ else
3055+ {
3056+ importType = MpcComets;
3057+ }
3058+
3059+ populateBookmarksList();
3060+
3061+ //Clear the fields
3062+ //ui->lineEditSingle->clear();
3063+ ui->lineEditFilePath->clear();
3064+ ui->lineEditURL->clear();
3065+
3066+ //If one of the options is selected, show the rest of the dialog
3067+ ui->groupBoxSource->setVisible(true);
3068+}
3069+
3070+void MpcImportWindow::markAll()
3071+{
3072+ QListWidget * const list = ui->listWidgetObjects;
3073+ int rowCount = list->count();
3074+ if (rowCount < 1)
3075+ return;
3076+
3077+ for (int row = 0; row < rowCount; row++)
3078+ {
3079+ QListWidgetItem * item = list->item(row);
3080+ if (item)
3081+ {
3082+ item->setCheckState(Qt::Checked);
3083+ }
3084+ }
3085+}
3086+
3087+void MpcImportWindow::unmarkAll()
3088+{
3089+ QListWidget * const list = ui->listWidgetObjects;
3090+ int rowCount = list->count();
3091+ if (rowCount < 1)
3092+ return;
3093+
3094+ for (int row = 0; row < rowCount; row++)
3095+ {
3096+ QListWidgetItem * item = list->item(row);
3097+ if (item)
3098+ {
3099+ item->setCheckState(Qt::Unchecked);
3100+ }
3101+ }
3102+}
3103+
3104+void MpcImportWindow::updateDownloadProgress(qint64 bytesReceived, qint64 bytesTotal)
3105+{
3106+ if (downloadProgressBar == NULL)
3107+ return;
3108+
3109+ int currentValue = 0;
3110+ int endValue = 0;
3111+
3112+ if (bytesTotal > -1 && bytesReceived <= bytesTotal)
3113+ {
3114+ //Round to the greatest possible derived unit
3115+ while (bytesTotal > 1024)
3116+ {
3117+ bytesReceived = std::floor(bytesReceived / 1024);
3118+ bytesTotal = std::floor(bytesTotal / 1024);
3119+ }
3120+ currentValue = bytesReceived;
3121+ endValue = bytesTotal;
3122+ }
3123+
3124+ downloadProgressBar->setValue(currentValue);
3125+ downloadProgressBar->setMaximum(endValue);
3126+}
3127+
3128+void MpcImportWindow::updateQueryProgress(qint64, qint64)
3129+{
3130+ if (queryProgressBar == NULL)
3131+ return;
3132+
3133+ //Just show activity
3134+ queryProgressBar->setValue(0);
3135+ queryProgressBar->setMaximum(0);
3136+}
3137+
3138+void MpcImportWindow::startDownload(QString urlString)
3139+{
3140+ if (downloadReply)
3141+ {
3142+ //There's already an operation in progress?
3143+ //TODO
3144+ return;
3145+ }
3146+
3147+ QUrl url(urlString);
3148+ if (!url.isValid() || url.isRelative() || url.scheme() != "http")
3149+ {
3150+ qWarning() << "Invalid URL:" << urlString;
3151+ return;
3152+ }
3153+ //qDebug() << url.toString();
3154+
3155+ //TODO: Interface changes!
3156+
3157+ downloadProgressBar = StelApp::getInstance().getGui()->addProgressBar();
3158+ downloadProgressBar->setValue(0);
3159+ downloadProgressBar->setMaximum(0);
3160+ //downloadProgressBar->setFormat("%v/%m");
3161+ downloadProgressBar->setVisible(true);
3162+
3163+ //TODO: Better handling of the interface
3164+ //dialog->setVisible(false);
3165+ enableInterface(false);
3166+ ui->pushButtonAbortDownload->setVisible(true);
3167+
3168+ connect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(downloadComplete(QNetworkReply*)));
3169+ downloadReply = networkManager->get(QNetworkRequest(url));
3170+ connect(downloadReply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(updateDownloadProgress(qint64,qint64)));
3171+}
3172+
3173+void MpcImportWindow::abortDownload()
3174+{
3175+ if (downloadReply == NULL || downloadReply->isFinished())
3176+ return;
3177+
3178+ qDebug() << "Aborting download...";
3179+
3180+ disconnect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(downloadComplete(QNetworkReply*)));
3181+ deleteDownloadProgressBar();
3182+
3183+ downloadReply->abort();
3184+ downloadReply->deleteLater();
3185+ downloadReply = NULL;
3186+
3187+ enableInterface(true);
3188+ ui->pushButtonAbortDownload->setVisible(false);
3189+}
3190+
3191+void MpcImportWindow::downloadComplete(QNetworkReply *reply)
3192+{
3193+ disconnect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(downloadComplete(QNetworkReply*)));
3194+ deleteDownloadProgressBar();
3195+ ui->pushButtonAbortDownload->setVisible(false);
3196+
3197+ /*
3198+ qDebug() << "reply->isOpen():" << reply->isOpen()
3199+ << "reply->isReadable():" << reply->isReadable()
3200+ << "reply->isFinished():" << reply->isFinished();
3201+ */
3202+
3203+ if(reply->error())
3204+ {
3205+ qWarning() << "Download error: While downloading"
3206+ << reply->url().toString()
3207+ << "the following error occured:"
3208+ << reply->errorString();
3209+ enableInterface(true);
3210+ reply->deleteLater();
3211+ downloadReply = NULL;
3212+ return;
3213+ }
3214+
3215+ QList<SsoElements> objects;
3216+ QTemporaryFile file;
3217+ if (file.open())
3218+ {
3219+ file.write(reply->readAll());
3220+ file.close();
3221+ objects = readElementsFromFile(importType, file.fileName());
3222+ }
3223+ else
3224+ {
3225+ qWarning() << "Unable to open a temporary file. Aborting operation.";
3226+ }
3227+
3228+ if (objects.isEmpty())
3229+ {
3230+ qWarning() << "No objects found in the file downloaded from"
3231+ << reply->url().toString();
3232+ }
3233+ else
3234+ {
3235+ //The request has been successful: add the URL to bookmarks?
3236+ if (ui->checkBoxAddBookmark->isChecked())
3237+ {
3238+ QString url = reply->url().toString();
3239+ QString title = ui->lineEditBookmarkTitle->text().trimmed();
3240+ //If no title has been entered, use the URL as a title
3241+ if (title.isEmpty())
3242+ title = url;
3243+ if (!bookmarks.value(importType).values().contains(url))
3244+ {
3245+ bookmarks[importType].insert(title, url);
3246+ populateBookmarksList();
3247+ saveBookmarks();
3248+ }
3249+ }
3250+ }
3251+
3252+ reply->deleteLater();
3253+ downloadReply = NULL;
3254+
3255+ //Temporary, until the slot/socket mechanism is ready
3256+ populateCandidateObjects(objects);
3257+ ui->stackedWidget->setCurrentIndex(1);
3258+ //As this window is persistent, if the Solar System is changed
3259+ //while there is a list, it should be reset.
3260+ connect(ssoManager, SIGNAL(solarSystemChanged()), this, SLOT(resetDialog()));
3261+}
3262+
3263+void MpcImportWindow::deleteDownloadProgressBar()
3264+{
3265+ disconnect(this, SLOT(updateDownloadProgress(qint64,qint64)));
3266+
3267+ if (downloadProgressBar)
3268+ {
3269+ downloadProgressBar->setVisible(false);
3270+ downloadProgressBar->deleteLater();
3271+ downloadProgressBar = NULL;
3272+ }
3273+}
3274+
3275+void MpcImportWindow::sendQuery()
3276+{
3277+ if (queryReply != NULL)
3278+ return;
3279+
3280+ QString query = ui->lineEditQuery->text().trimmed();
3281+ if (query.isEmpty())
3282+ return;
3283+
3284+ //Progress bar
3285+ queryProgressBar = StelApp::getInstance().getGui()->addProgressBar();
3286+ queryProgressBar->setValue(0);
3287+ queryProgressBar->setMaximum(0);
3288+ queryProgressBar->setFormat("Searching...");
3289+ queryProgressBar->setVisible(true);
3290+
3291+ //TODO: Better handling of the interface
3292+ enableInterface(false);
3293+ ui->labelQueryMessage->setVisible(false);
3294+
3295+ QUrl url;
3296+ url.addQueryItem("ty","e");//Type: ephemerides
3297+ url.addQueryItem("TextArea", query);//Object name query
3298+ //url.addQueryItem("e", "-1");//Elements format: MPC 1-line
3299+ url.addQueryItem("e", "3");//Elements format: XEphem
3300+ //Yes, all of the rest are necessary
3301+ url.addQueryItem("d","");
3302+ url.addQueryItem("l","");
3303+ url.addQueryItem("i","");
3304+ url.addQueryItem("u","d");
3305+ url.addQueryItem("uto", "0");
3306+ url.addQueryItem("c", "");
3307+ url.addQueryItem("long", "");
3308+ url.addQueryItem("lat", "");
3309+ url.addQueryItem("alt", "");
3310+ url.addQueryItem("raty", "a");
3311+ url.addQueryItem("s", "t");
3312+ url.addQueryItem("m", "m");
3313+ url.addQueryItem("adir", "S");
3314+ url.addQueryItem("oed", "");
3315+ url.addQueryItem("resoc", "");
3316+ url.addQueryItem("tit", "");
3317+ url.addQueryItem("bu", "");
3318+ url.addQueryItem("ch", "c");
3319+ url.addQueryItem("ce", "f");
3320+ url.addQueryItem("js", "f");
3321+
3322+ QNetworkRequest request(QUrl("http://scully.cfa.harvard.edu/~cgi/MPEph2"));
3323+ request.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded");//Is this really necessary?
3324+ request.setHeader(QNetworkRequest::ContentLengthHeader, url.encodedQuery().length());
3325+
3326+ startCountdown();
3327+ ui->pushButtonAbortQuery->setVisible(true);
3328+ connect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(queryComplete(QNetworkReply*)));
3329+ queryReply = networkManager->post(request, url.encodedQuery());
3330+ connect(queryReply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(updateQueryProgress(qint64,qint64)));
3331+}
3332+
3333+void MpcImportWindow::abortQuery()
3334+{
3335+ if (queryReply == NULL)
3336+ return;
3337+
3338+ disconnect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(queryComplete(QNetworkReply*)));
3339+ deleteQueryProgressBar();
3340+
3341+ queryReply->abort();
3342+ queryReply->deleteLater();
3343+ queryReply = NULL;
3344+
3345+ //resetCountdown();
3346+ enableInterface(true);
3347+ ui->pushButtonAbortQuery->setVisible(false);
3348+}
3349+
3350+void MpcImportWindow::queryComplete(QNetworkReply *reply)
3351+{
3352+ disconnect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(queryComplete(QNetworkReply*)));
3353+ deleteQueryProgressBar();
3354+
3355+ //Hide the abort button - a reply has been received
3356+ ui->pushButtonAbortQuery->setVisible(false);
3357+
3358+ if (reply->error())
3359+ {
3360+ qWarning() << "Download error: While trying to access"
3361+ << reply->url().toString()
3362+ << "the following error occured:"
3363+ << reply->errorString();
3364+ ui->labelQueryMessage->setText(reply->errorString());//TODO: Decide if this is a good idea
3365+ ui->labelQueryMessage->setVisible(true);
3366+ enableInterface(true);
3367+
3368+ reply->deleteLater();
3369+ queryReply = NULL;
3370+ return;
3371+ }
3372+
3373+ if (reply->header(QNetworkRequest::ContentTypeHeader) != "text/ascii" ||
3374+ reply->rawHeader(QByteArray("Content-disposition")) != "attachment; filename=elements.txt")
3375+ {
3376+ ui->labelQueryMessage->setText("Object not found.");
3377+ ui->labelQueryMessage->setVisible(true);
3378+ enableInterface(true);
3379+ }
3380+ else
3381+ {
3382+ QList<SsoElements> objects;
3383+ QTemporaryFile file;
3384+ if (file.open())
3385+ {
3386+ file.write(reply->readAll());
3387+ file.close();
3388+
3389+ /*
3390+ //Try to read it as a comet first?
3391+ objects = readElementsFromFile(MpcComets, file.fileName());
3392+ if (objects.isEmpty())
3393+ objects = readElementsFromFile(MpcMinorPlanets, file.fileName());
3394+ */
3395+ objects = ssoManager->readXEphemOneLineElementsFromFile(file.fileName());
3396+ }
3397+ else
3398+ {
3399+ qWarning() << "Unable to open a temporary file. Aborting operation.";
3400+ }
3401+
3402+ if (objects.isEmpty())
3403+ {
3404+ qWarning() << "No objects found in the file downloaded from"
3405+ << reply->url().toString();
3406+ }
3407+ else
3408+ {
3409+ //The request has been successful: add the URL to bookmarks?
3410+ if (ui->checkBoxAddBookmark->isChecked())
3411+ {
3412+ QString url = reply->url().toString();
3413+ if (!bookmarks.value(importType).values().contains(url))
3414+ {
3415+ //Use the URL as a title for now
3416+ bookmarks[importType].insert(url, url);
3417+ }
3418+ }
3419+
3420+ //Temporary, until the slot/socket mechanism is ready
3421+ populateCandidateObjects(objects);
3422+ ui->stackedWidget->setCurrentIndex(1);
3423+ }
3424+ }
3425+
3426+ reply->deleteLater();
3427+ queryReply = NULL;
3428+}
3429+
3430+void MpcImportWindow::deleteQueryProgressBar()
3431+{
3432+ disconnect(this, SLOT(updateQueryProgress(qint64,qint64)));
3433+ if (queryProgressBar)
3434+ {
3435+ queryProgressBar->setVisible(false);
3436+ queryProgressBar->deleteLater();
3437+ queryProgressBar = NULL;
3438+ }
3439+}
3440+
3441+void MpcImportWindow::startCountdown()
3442+{
3443+ if (!countdownTimer->isActive())
3444+ countdownTimer->start(1000);//1 second
3445+
3446+ //Disable the interface
3447+ ui->lineEditQuery->setEnabled(false);
3448+ ui->pushButtonSendQuery->setEnabled(false);
3449+}
3450+
3451+void MpcImportWindow::resetCountdown()
3452+{
3453+ //Stop the timer
3454+ if (countdownTimer->isActive())
3455+ {
3456+ countdownTimer->stop();
3457+
3458+ //If the query is still active, kill it
3459+ if (queryReply != NULL && queryReply->isRunning())
3460+ {
3461+ abortQuery();
3462+ ui->labelQueryMessage->setText("The query timed out. You can try again, now or later.");
3463+ ui->labelQueryMessage->setVisible(true);
3464+ }
3465+ }
3466+
3467+ //Reset the counter
3468+ countdown = 60;
3469+
3470+ //Enable the interface
3471+ ui->lineEditQuery->setEnabled(true);
3472+ ui->pushButtonSendQuery->setEnabled(true);
3473+}
3474+
3475+void MpcImportWindow::updateCountdown()
3476+{
3477+ --countdown;
3478+ if (countdown < 0)
3479+ {
3480+ resetCountdown();
3481+ }
3482+ //If there has been an answer
3483+ else if (countdown > 50 && queryReply == NULL)
3484+ {
3485+ resetCountdown();
3486+ }
3487+}
3488+
3489+void MpcImportWindow::resetNotFound()
3490+{
3491+ ui->labelQueryMessage->setVisible(false);
3492+}
3493+
3494+void MpcImportWindow::loadBookmarks()
3495+{
3496+ bookmarks[MpcComets].clear();
3497+ bookmarks[MpcMinorPlanets].clear();
3498+
3499+ QString bookmarksFilePath(StelFileMgr::getUserDir() + "/modules/SolarSystemEditor/bookmarks.json");
3500+ if (StelFileMgr::isReadable(bookmarksFilePath))
3501+ {
3502+ QFile bookmarksFile(bookmarksFilePath);
3503+ if (bookmarksFile.open(QFile::ReadOnly | QFile::Text))
3504+ {
3505+ QVariantMap jsonRoot = StelJsonParser::parse(bookmarksFile.readAll()).toMap();
3506+
3507+ loadBookmarksGroup(jsonRoot.value("mpcMinorPlanets").toMap(), bookmarks[MpcMinorPlanets]);
3508+ loadBookmarksGroup(jsonRoot.value("mpcComets").toMap(), bookmarks[MpcComets]);
3509+
3510+ bookmarksFile.close();
3511+
3512+ //If nothing was read, continue
3513+ if (!bookmarks.value(MpcComets).isEmpty() && !bookmarks[MpcMinorPlanets].isEmpty())
3514+ return;
3515+ }
3516+ }
3517+
3518+ qDebug() << "Bookmarks file can't be read. Hard-coded bookmarks will be used.";
3519+
3520+ //Initialize with hard-coded values
3521+ bookmarks[MpcMinorPlanets].insert("MPC's list of bright minor planets at opposition", "http://www.minorplanetcenter.org/iau/Ephemerides/Bright/2010/Soft00Bright.txt");
3522+ bookmarks[MpcMinorPlanets].insert("MPCORB: near-Earth asteroids (NEAs)", "http://www.minorplanetcenter.org/iau/MPCORB/NEA.txt");
3523+ bookmarks[MpcMinorPlanets].insert("MPCORB: potentially hazardous asteroids (PHAs)", "http://www.minorplanetcenter.org/iau/MPCORB/PHA.txt");
3524+ bookmarks[MpcComets].insert("MPC's list of observable comets", "http://www.minorplanetcenter.org/iau/Ephemerides/Comets/Soft00Cmt.txt");
3525+
3526+ //Try to save them to a file
3527+ saveBookmarks();
3528+}
3529+
3530+void MpcImportWindow::loadBookmarksGroup(QVariantMap source, Bookmarks & bookmarkGroup)
3531+{
3532+ if (source.isEmpty())
3533+ return;
3534+
3535+ foreach (QString title, source.keys())
3536+ {
3537+ QString url = source.value(title).toString();
3538+ if (!url.isEmpty())
3539+ bookmarkGroup.insert(title, url);
3540+ }
3541+}
3542+
3543+void MpcImportWindow::saveBookmarks()
3544+{
3545+ try
3546+ {
3547+ StelFileMgr::makeSureDirExistsAndIsWritable(StelFileMgr::getUserDir() + "/modules/SolarSystemEditor");
3548+
3549+ QVariantMap jsonRoot;
3550+
3551+ QString bookmarksFilePath(StelFileMgr::getUserDir() + "/modules/SolarSystemEditor/bookmarks.json");
3552+
3553+ //If the file exists, load it first
3554+ if (StelFileMgr::isReadable(bookmarksFilePath))
3555+ {
3556+ QFile bookmarksFile(bookmarksFilePath);
3557+ if (bookmarksFile.open(QFile::ReadOnly | QFile::Text))
3558+ {
3559+ jsonRoot = StelJsonParser::parse(bookmarksFile.readAll()).toMap();
3560+ bookmarksFile.close();
3561+ }
3562+ }
3563+
3564+ QFile bookmarksFile(bookmarksFilePath);
3565+ if (bookmarksFile.open(QFile::WriteOnly | QFile::Truncate | QFile::Text))
3566+ {
3567+ QVariantMap minorPlanetsObject;
3568+ saveBookmarksGroup(bookmarks[MpcMinorPlanets], minorPlanetsObject);
3569+ //qDebug() << minorPlanetsObject.keys();
3570+ jsonRoot.insert("mpcMinorPlanets", minorPlanetsObject);
3571+
3572+ QVariantMap cometsObject;
3573+ saveBookmarksGroup(bookmarks[MpcComets], cometsObject);
3574+ jsonRoot.insert("mpcComets", cometsObject);
3575+
3576+ StelJsonParser::write(jsonRoot, &bookmarksFile);
3577+ bookmarksFile.close();
3578+
3579+ qDebug() << "Bookmarks file saved to" << bookmarksFilePath;
3580+ return;
3581+ }
3582+ else
3583+ {
3584+ qDebug() << "Unable to write bookmarks file to" << bookmarksFilePath;
3585+ }
3586+ }
3587+ catch (std::exception & e)
3588+ {
3589+ qDebug() << "Unable to save bookmarks file:" << e.what();
3590+ }
3591+}
3592+
3593+void MpcImportWindow::saveBookmarksGroup(Bookmarks & bookmarkGroup, QVariantMap & output)
3594+{
3595+ foreach (QString title, bookmarkGroup.keys())
3596+ {
3597+ output.insert(title, bookmarkGroup.value(title));
3598+ }
3599+}
3600
3601=== added file 'plugins/SolarSystemEditor/src/gui/MpcImportWindow.hpp'
3602--- plugins/SolarSystemEditor/src/gui/MpcImportWindow.hpp 1970-01-01 00:00:00 +0000
3603+++ plugins/SolarSystemEditor/src/gui/MpcImportWindow.hpp 2010-11-16 20:06:17 +0000
3604@@ -0,0 +1,135 @@
3605+/*
3606+ * Solar System editor plug-in for Stellarium
3607+ *
3608+ * Copyright (C) 2010 Bogdan Marinov
3609+ *
3610+ * This program is free software; you can redistribute it and/or
3611+ * modify it under the terms of the GNU General Public License
3612+ * as published by the Free Software Foundation; either version 2
3613+ * of the License, or (at your option) any later version.
3614+ *
3615+ * This program is distributed in the hope that it will be useful,
3616+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3617+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3618+ * GNU General Public License for more details.
3619+ *
3620+ * You should have received a copy of the GNU General Public License
3621+ * along with this program; if not, write to the Free Software
3622+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
3623+ */
3624+
3625+#ifndef _MPC_IMPORT_WINDOW_
3626+#define _MPC_IMPORT_WINDOW_
3627+
3628+#include <QObject>
3629+#include "StelDialog.hpp"
3630+
3631+#include "SolarSystemEditor.hpp"
3632+
3633+class Ui_mpcImportWindow;
3634+class QNetworkAccessManager;
3635+class QNetworkReply;
3636+class QProgressBar;
3637+
3638+/*! \brief Window for importing orbital elements from various sources.
3639+ \author Bogdan Marinov
3640+*/
3641+class MpcImportWindow : public StelDialog
3642+{
3643+ Q_OBJECT
3644+public:
3645+ enum ImportType {
3646+ MpcComets,
3647+ MpcMinorPlanets
3648+ };
3649+
3650+ MpcImportWindow();
3651+ virtual ~MpcImportWindow();
3652+ void languageChanged();
3653+
3654+signals:
3655+ void objectsImported();
3656+
3657+private slots:
3658+ //Radio buttons for type
3659+ void switchImportType(bool checked);
3660+
3661+ //File
3662+ void selectFile();
3663+
3664+ //Download
3665+ void pasteClipboardURL();
3666+ void bookmarkSelected(QString);
3667+
3668+ //Buttons for the list tab
3669+ void acquireObjectData();
3670+ void abortDownload();
3671+
3672+ //Online search
3673+ void sendQuery();
3674+ void abortQuery();
3675+ void updateCountdown();
3676+ void resetNotFound();
3677+
3678+ //Network
3679+ void updateDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
3680+ void updateQueryProgress(qint64 bytesReceived, qint64 bytesTotal);
3681+ void downloadComplete(QNetworkReply * reply);
3682+ void queryComplete(QNetworkReply * reply);
3683+
3684+ //! Marks (checks) all items in the results lists
3685+ void markAll();
3686+ //! Unmarks (unchecks) all items in the results lists
3687+ void unmarkAll();
3688+ void addObjects();
3689+ void discardObjects();
3690+
3691+ //! resets the dialog to the state it should be in immediately after createDialogContent();.
3692+ void resetDialog();
3693+
3694+private:
3695+ SolarSystemEditor * ssoManager;
3696+ QList<SsoElements> candidatesForAddition;
3697+ QList<SsoElements> candidatesForUpdate;
3698+
3699+ ImportType importType;
3700+
3701+ //! wrapper for the single object function to allow multiple formats.
3702+ SsoElements readElementsFromString(QString elements);
3703+ //! wrapper for the file function to allow multiple formats
3704+ QList<SsoElements> readElementsFromFile(ImportType type, QString filePath);
3705+
3706+ void populateBookmarksList();
3707+ //void populateCandidateObjects();
3708+ void populateCandidateObjects(QList<SsoElements>);
3709+ void enableInterface(bool enable);
3710+
3711+ //Downloading
3712+ QNetworkAccessManager * networkManager;
3713+ QNetworkReply * downloadReply;
3714+ QNetworkReply * queryReply;
3715+ QProgressBar * downloadProgressBar;
3716+ QProgressBar * queryProgressBar;
3717+ void startDownload(QString url);
3718+ void deleteDownloadProgressBar();
3719+ void deleteQueryProgressBar();
3720+
3721+ typedef QHash<QString,QString> Bookmarks;
3722+ QHash<ImportType, Bookmarks> bookmarks;
3723+ void loadBookmarks();
3724+ void loadBookmarksGroup(QVariantMap source, Bookmarks & bookmarkGroup);
3725+ void saveBookmarks();
3726+ void saveBookmarksGroup(Bookmarks & bookmarkGroup, QVariantMap & output);
3727+
3728+ //Online search
3729+ int countdown;
3730+ QTimer * countdownTimer;
3731+ void startCountdown();
3732+ void resetCountdown();
3733+
3734+protected:
3735+ virtual void createDialogContent();
3736+ Ui_mpcImportWindow * ui;
3737+};
3738+
3739+#endif //_MPC_IMPORT_WINDOW_
3740
3741=== added file 'plugins/SolarSystemEditor/src/gui/SolarSystemManagerWindow.cpp'
3742--- plugins/SolarSystemEditor/src/gui/SolarSystemManagerWindow.cpp 1970-01-01 00:00:00 +0000
3743+++ plugins/SolarSystemEditor/src/gui/SolarSystemManagerWindow.cpp 2010-11-16 20:06:17 +0000
3744@@ -0,0 +1,170 @@
3745+/*
3746+ * Solar System editor plug-in for Stellarium
3747+ *
3748+ * Copyright (C) 2010 Bogdan Marinov
3749+ *
3750+ * This program is free software; you can redistribute it and/or
3751+ * modify it under the terms of the GNU General Public License
3752+ * as published by the Free Software Foundation; either version 2
3753+ * of the License, or (at your option) any later version.
3754+ *
3755+ * This program is distributed in the hope that it will be useful,
3756+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3757+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3758+ * GNU General Public License for more details.
3759+ *
3760+ * You should have received a copy of the GNU General Public License
3761+ * along with this program; if not, write to the Free Software
3762+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
3763+ */
3764+
3765+#include "SolarSystemEditor.hpp"
3766+
3767+#include "SolarSystemManagerWindow.hpp"
3768+#include "ui_solarSystemManagerWindow.h"
3769+
3770+#include "MpcImportWindow.hpp"
3771+#include "ManualImportWindow.hpp"
3772+
3773+#include "StelApp.hpp"
3774+#include "StelFileMgr.hpp"
3775+#include "StelModuleMgr.hpp"
3776+#include "Planet.hpp"
3777+#include "SolarSystem.hpp"
3778+
3779+#include <QFileDialog>
3780+
3781+SolarSystemManagerWindow::SolarSystemManagerWindow()
3782+{
3783+ ui = new Ui_solarSystemManagerWindow();
3784+ mpcImportWindow = new MpcImportWindow();
3785+ manualImportWindow = NULL;
3786+
3787+ ssoManager = GETSTELMODULE(SolarSystemEditor);
3788+}
3789+
3790+SolarSystemManagerWindow::~SolarSystemManagerWindow()
3791+{
3792+ delete ui;
3793+
3794+ if (mpcImportWindow)
3795+ delete mpcImportWindow;
3796+ if (manualImportWindow)
3797+ delete manualImportWindow;
3798+}
3799+
3800+void SolarSystemManagerWindow::createDialogContent()
3801+{
3802+ ui->setupUi(dialog);
3803+
3804+ //Signals
3805+ connect(ui->closeStelWindow, SIGNAL(clicked()), this, SLOT(close()));
3806+ connect(ui->pushButtonCopyFile, SIGNAL(clicked()), this, SLOT(copyConfiguration()));
3807+ connect(ui->pushButtonReplaceFile, SIGNAL(clicked()), this, SLOT(replaceConfiguration()));
3808+ connect(ui->pushButtonRemove, SIGNAL(clicked()), this, SLOT(removeObject()));
3809+ connect(ui->pushButtonImportMPC, SIGNAL(clicked()), this, SLOT(newImportMPC()));
3810+ connect(ui->pushButtonManual, SIGNAL(clicked()), this, SLOT(newImportManual()));
3811+
3812+ connect(ssoManager, SIGNAL(solarSystemChanged()), this, SLOT(populateSolarSystemList()));
3813+ connect(ui->pushButtonReset, SIGNAL(clicked()), ssoManager, SLOT(resetSolarSystemToDefault()));
3814+
3815+ ui->labelVersion->setText(QString("Version %1").arg(PLUGIN_VERSION));
3816+ //Remove the "Data Import" tab
3817+ //TODO: (temporary, until the ManualImportWindow is finished)
3818+ ui->tabWidget->removeTab(2);
3819+
3820+ Q_ASSERT(mpcImportWindow);
3821+ //Rebuild the list if any planets have been imported
3822+ connect(mpcImportWindow, SIGNAL(objectsImported()), this, SLOT(populateSolarSystemList()));
3823+
3824+ ui->lineEditUserFilePath->setText(ssoManager->getCustomSolarSystemFilePath());
3825+ populateSolarSystemList();
3826+}
3827+
3828+void SolarSystemManagerWindow::languageChanged()
3829+{
3830+ if (dialog)
3831+ {
3832+ ui->retranslateUi(dialog);
3833+ populateSolarSystemList();
3834+ ui->labelVersion->setText(QString("Version %1").arg(PLUGIN_VERSION));
3835+ }
3836+
3837+ if (mpcImportWindow)
3838+ mpcImportWindow->languageChanged();
3839+}
3840+
3841+void SolarSystemManagerWindow::newImportMPC()
3842+{
3843+ Q_ASSERT(mpcImportWindow);
3844+
3845+ mpcImportWindow->setVisible(true);
3846+}
3847+
3848+void SolarSystemManagerWindow::newImportManual()
3849+{
3850+ if (manualImportWindow == NULL)
3851+ {
3852+ manualImportWindow = new ManualImportWindow();
3853+ connect(manualImportWindow, SIGNAL(visibleChanged(bool)), this, SLOT(resetImportManual(bool)));
3854+ }
3855+
3856+ manualImportWindow->setVisible(true);
3857+}
3858+
3859+void SolarSystemManagerWindow::resetImportManual(bool show)
3860+{
3861+ //If the window is being displayed, do nothing
3862+ if (show)
3863+ return;
3864+
3865+ if (manualImportWindow)
3866+ {
3867+ //TODO:Move this out of here!
3868+ //Reload the list, in case there are new objects
3869+ populateSolarSystemList();
3870+
3871+ delete manualImportWindow;
3872+ manualImportWindow = NULL;
3873+
3874+ //This window is in the background, bring it to the foreground
3875+ dialog->setVisible(true);
3876+ }
3877+}
3878+
3879+void SolarSystemManagerWindow::populateSolarSystemList()
3880+{
3881+ unlocalizedNames.clear();
3882+ foreach (const PlanetP & object, GETSTELMODULE(SolarSystem)->getAllPlanets())
3883+ {
3884+ unlocalizedNames.insert(object->getNameI18n(), object->getEnglishName());
3885+ }
3886+
3887+ ui->listWidgetObjects->clear();
3888+ ui->listWidgetObjects->addItems(unlocalizedNames.keys());
3889+ //No explicit sorting is necessary: sortingEnabled is set in the .ui
3890+}
3891+
3892+void SolarSystemManagerWindow::removeObject()
3893+{
3894+ if(ui->listWidgetObjects->currentItem())
3895+ {
3896+ QString ssoI18nName = ui->listWidgetObjects->currentItem()->text();
3897+ QString ssoEnglishName = unlocalizedNames.value(ssoI18nName);
3898+ //qDebug() << ssoId;
3899+ //TODO: Ask for confirmation first?
3900+ ssoManager->removeSsoWithName(ssoEnglishName);
3901+ }
3902+}
3903+
3904+void SolarSystemManagerWindow::copyConfiguration()
3905+{
3906+ QString filePath = QFileDialog::getSaveFileName(0, "Save the Solar System configuration file as...", StelFileMgr::getDesktopDir());
3907+ ssoManager->copySolarSystemConfigurationFileTo(filePath);
3908+}
3909+
3910+void SolarSystemManagerWindow::replaceConfiguration()
3911+{
3912+ QString filePath = QFileDialog::getOpenFileName(0, "Select a file to replace the Solar System configuration file", StelFileMgr::getDesktopDir(), QString("Configration files (*.ini)"));
3913+ ssoManager->replaceSolarSystemConfigurationFileWith(filePath);
3914+}
3915
3916=== added file 'plugins/SolarSystemEditor/src/gui/SolarSystemManagerWindow.hpp'
3917--- plugins/SolarSystemEditor/src/gui/SolarSystemManagerWindow.hpp 1970-01-01 00:00:00 +0000
3918+++ plugins/SolarSystemEditor/src/gui/SolarSystemManagerWindow.hpp 2010-11-16 20:06:17 +0000
3919@@ -0,0 +1,73 @@
3920+/*
3921+ * Solar System editor plug-in for Stellarium
3922+ *
3923+ * Copyright (C) 2010 Bogdan Marinov
3924+ *
3925+ * This program is free software; you can redistribute it and/or
3926+ * modify it under the terms of the GNU General Public License
3927+ * as published by the Free Software Foundation; either version 2
3928+ * of the License, or (at your option) any later version.
3929+ *
3930+ * This program is distributed in the hope that it will be useful,
3931+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3932+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3933+ * GNU General Public License for more details.
3934+ *
3935+ * You should have received a copy of the GNU General Public License
3936+ * along with this program; if not, write to the Free Software
3937+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
3938+ */
3939+
3940+#ifndef _SOLAR_SYSTEM_MANAGER_WINDOW_
3941+#define _SOLAR_SYSTEM_MANAGER_WINDOW_
3942+
3943+#include <QObject>
3944+#include "StelDialog.hpp"
3945+
3946+#include <QHash>
3947+#include <QString>
3948+
3949+class SolarSystemEditor;
3950+
3951+class Ui_solarSystemManagerWindow;
3952+class MpcImportWindow;
3953+class ManualImportWindow;
3954+
3955+/*! \brief Main window for handling Solar System objects.
3956+ \author Bogdan Marinov
3957+*/
3958+class SolarSystemManagerWindow : public StelDialog
3959+{
3960+ Q_OBJECT
3961+public:
3962+ SolarSystemManagerWindow();
3963+ virtual ~SolarSystemManagerWindow();
3964+ void languageChanged();
3965+
3966+protected:
3967+ virtual void createDialogContent();
3968+ Ui_solarSystemManagerWindow * ui;
3969+
3970+private slots:
3971+ //! \todo Find a way to suggest a default file name (select directory instead of file?)
3972+ void copyConfiguration();
3973+ void replaceConfiguration();
3974+
3975+ void populateSolarSystemList();
3976+ void removeObject();
3977+
3978+ void newImportMPC();
3979+
3980+ void newImportManual();
3981+ void resetImportManual(bool);
3982+
3983+private:
3984+ MpcImportWindow* mpcImportWindow;
3985+ ManualImportWindow * manualImportWindow;
3986+
3987+ SolarSystemEditor * ssoManager;
3988+
3989+ QHash<QString,QString> unlocalizedNames;
3990+};
3991+
3992+#endif //_SOLAR_SYSTEM_MANAGER_WINDOW_
3993
3994=== added file 'plugins/SolarSystemEditor/src/gui/manualImportWindow.ui'
3995--- plugins/SolarSystemEditor/src/gui/manualImportWindow.ui 1970-01-01 00:00:00 +0000
3996+++ plugins/SolarSystemEditor/src/gui/manualImportWindow.ui 2010-11-16 20:06:17 +0000
3997@@ -0,0 +1,890 @@
3998+<?xml version="1.0" encoding="UTF-8"?>
3999+<ui version="4.0">
4000+ <class>manualImportWindow</class>
4001+ <widget class="QWidget" name="manualImportWindow">
4002+ <property name="geometry">
4003+ <rect>
4004+ <x>0</x>
4005+ <y>0</y>
4006+ <width>600</width>
4007+ <height>500</height>
4008+ </rect>
4009+ </property>
4010+ <layout class="QGridLayout" name="gridLayoutWindow">
4011+ <property name="margin">
4012+ <number>0</number>
4013+ </property>
4014+ <property name="spacing">
4015+ <number>0</number>
4016+ </property>
4017+ <item row="0" column="0" colspan="2">
4018+ <widget class="BarFrame" name="LocationBar">
4019+ <property name="sizePolicy">
4020+ <sizepolicy hsizetype="Expanding" vsizetype="Minimum">
4021+ <horstretch>0</horstretch>
4022+ <verstretch>0</verstretch>
4023+ </sizepolicy>
4024+ </property>
4025+ <property name="minimumSize">
4026+ <size>
4027+ <width>0</width>
4028+ <height>25</height>
4029+ </size>
4030+ </property>
4031+ <property name="maximumSize">
4032+ <size>
4033+ <width>16777215</width>
4034+ <height>30</height>
4035+ </size>
4036+ </property>
4037+ <property name="focusPolicy">
4038+ <enum>Qt::NoFocus</enum>
4039+ </property>
4040+ <property name="autoFillBackground">
4041+ <bool>false</bool>
4042+ </property>
4043+ <property name="frameShape">
4044+ <enum>QFrame::StyledPanel</enum>
4045+ </property>
4046+ <layout class="QHBoxLayout" name="_2">
4047+ <property name="spacing">
4048+ <number>6</number>
4049+ </property>
4050+ <property name="leftMargin">
4051+ <number>0</number>
4052+ </property>
4053+ <property name="topMargin">
4054+ <number>0</number>
4055+ </property>
4056+ <property name="rightMargin">
4057+ <number>4</number>
4058+ </property>
4059+ <property name="bottomMargin">
4060+ <number>0</number>
4061+ </property>
4062+ <item>
4063+ <spacer name="leftSpacer">
4064+ <property name="orientation">
4065+ <enum>Qt::Horizontal</enum>
4066+ </property>
4067+ <property name="sizeHint" stdset="0">
4068+ <size>
4069+ <width>40</width>
4070+ <height>20</height>
4071+ </size>
4072+ </property>
4073+ </spacer>
4074+ </item>
4075+ <item>
4076+ <widget class="QLabel" name="stelWindowTitle">
4077+ <property name="text">
4078+ <string notr="true" extracomment="The title of the window will be set during runtime">Define an object</string>
4079+ </property>
4080+ </widget>
4081+ </item>
4082+ <item>
4083+ <spacer name="rightSpacer">
4084+ <property name="orientation">
4085+ <enum>Qt::Horizontal</enum>
4086+ </property>
4087+ <property name="sizeHint" stdset="0">
4088+ <size>
4089+ <width>40</width>
4090+ <height>20</height>
4091+ </size>
4092+ </property>
4093+ </spacer>
4094+ </item>
4095+ <item>
4096+ <widget class="QPushButton" name="closeStelWindow">
4097+ <property name="minimumSize">
4098+ <size>
4099+ <width>16</width>
4100+ <height>16</height>
4101+ </size>
4102+ </property>
4103+ <property name="maximumSize">
4104+ <size>
4105+ <width>16</width>
4106+ <height>16</height>
4107+ </size>
4108+ </property>
4109+ <property name="focusPolicy">
4110+ <enum>Qt::NoFocus</enum>
4111+ </property>
4112+ <property name="text">
4113+ <string/>
4114+ </property>
4115+ </widget>
4116+ </item>
4117+ </layout>
4118+ </widget>
4119+ </item>
4120+ <item row="1" column="1">
4121+ <widget class="QGroupBox" name="groupBoxObjectType">
4122+ <property name="title">
4123+ <string>Object type</string>
4124+ </property>
4125+ <property name="alignment">
4126+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
4127+ </property>
4128+ <layout class="QVBoxLayout" name="verticalLayoutObjectType">
4129+ <property name="margin">
4130+ <number>0</number>
4131+ </property>
4132+ <item>
4133+ <widget class="QRadioButton" name="radioButtonSolarSystemObject">
4134+ <property name="text">
4135+ <string>Solar System object</string>
4136+ </property>
4137+ </widget>
4138+ </item>
4139+ <item>
4140+ <widget class="QRadioButton" name="radioButtonMinorPlanet">
4141+ <property name="text">
4142+ <string>Minor planet (asteroid)</string>
4143+ </property>
4144+ </widget>
4145+ </item>
4146+ <item>
4147+ <widget class="QRadioButton" name="radioButtonComet">
4148+ <property name="text">
4149+ <string>Comet</string>
4150+ </property>
4151+ </widget>
4152+ </item>
4153+ <item>
4154+ <widget class="QRadioButton" name="radioButtonSatellite">
4155+ <property name="text">
4156+ <string>Satellite</string>
4157+ </property>
4158+ </widget>
4159+ </item>
4160+ </layout>
4161+ </widget>
4162+ </item>
4163+ <item row="1" column="0">
4164+ <widget class="QGroupBox" name="groupBoxName">
4165+ <property name="title">
4166+ <string>Name</string>
4167+ </property>
4168+ <property name="alignment">
4169+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
4170+ </property>
4171+ <layout class="QGridLayout" name="gridLayoutName">
4172+ <property name="margin">
4173+ <number>0</number>
4174+ </property>
4175+ <item row="0" column="0">
4176+ <widget class="QLabel" name="labelName">
4177+ <property name="text">
4178+ <string>Name</string>
4179+ </property>
4180+ </widget>
4181+ </item>
4182+ <item row="0" column="1">
4183+ <widget class="QLineEdit" name="lineEditName"/>
4184+ </item>
4185+ <item row="1" column="0">
4186+ <widget class="QLabel" name="labelIdentifier">
4187+ <property name="text">
4188+ <string>Identifier</string>
4189+ </property>
4190+ </widget>
4191+ </item>
4192+ <item row="1" column="1">
4193+ <widget class="QLineEdit" name="lineEditIdentifier"/>
4194+ </item>
4195+ <item row="2" column="0">
4196+ <widget class="QCheckBox" name="checkBoxMinorPlanetNumber">
4197+ <property name="text">
4198+ <string>Minor planet number</string>
4199+ </property>
4200+ </widget>
4201+ </item>
4202+ <item row="2" column="1">
4203+ <widget class="QLineEdit" name="lineEditMinorPlanetNumber"/>
4204+ </item>
4205+ </layout>
4206+ </widget>
4207+ </item>
4208+ <item row="2" column="0" colspan="2">
4209+ <widget class="QScrollArea" name="scrollArea">
4210+ <property name="widgetResizable">
4211+ <bool>true</bool>
4212+ </property>
4213+ <property name="alignment">
4214+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
4215+ </property>
4216+ <widget class="QWidget" name="scrollAreaWidgetContents">
4217+ <property name="geometry">
4218+ <rect>
4219+ <x>0</x>
4220+ <y>0</y>
4221+ <width>582</width>
4222+ <height>1436</height>
4223+ </rect>
4224+ </property>
4225+ <layout class="QVBoxLayout" name="verticalLayoutScroll">
4226+ <property name="margin">
4227+ <number>0</number>
4228+ </property>
4229+ <item>
4230+ <widget class="QGroupBox" name="groupBoxProperties">
4231+ <property name="title">
4232+ <string>Properties</string>
4233+ </property>
4234+ <layout class="QGridLayout" name="gridLayout_4">
4235+ <item row="0" column="0">
4236+ <widget class="QLabel" name="labelParent">
4237+ <property name="text">
4238+ <string>Parent:</string>
4239+ </property>
4240+ </widget>
4241+ </item>
4242+ <item row="0" column="2" colspan="2">
4243+ <widget class="QComboBox" name="comboBoxParent"/>
4244+ </item>
4245+ <item row="1" column="0">
4246+ <widget class="QLabel" name="labelRadius">
4247+ <property name="text">
4248+ <string>Radius:</string>
4249+ </property>
4250+ </widget>
4251+ </item>
4252+ <item row="1" column="2" colspan="2">
4253+ <widget class="QLineEdit" name="lineEditRadius"/>
4254+ </item>
4255+ <item row="2" column="0">
4256+ <widget class="QLabel" name="labelOblateness">
4257+ <property name="text">
4258+ <string>Oblateness:</string>
4259+ </property>
4260+ </widget>
4261+ </item>
4262+ <item row="2" column="2" colspan="2">
4263+ <widget class="QLineEdit" name="lineEditOblateness"/>
4264+ </item>
4265+ <item row="3" column="0">
4266+ <widget class="QLabel" name="labelAlbedo">
4267+ <property name="text">
4268+ <string>Albedo:</string>
4269+ </property>
4270+ </widget>
4271+ </item>
4272+ <item row="3" column="2" colspan="2">
4273+ <widget class="QLineEdit" name="lineEditAlbedo"/>
4274+ </item>
4275+ <item row="4" column="0">
4276+ <widget class="QLabel" name="labelColor">
4277+ <property name="text">
4278+ <string>Color:</string>
4279+ </property>
4280+ </widget>
4281+ </item>
4282+ <item row="4" column="3">
4283+ <widget class="QPushButton" name="pushButtonSelectColor"/>
4284+ </item>
4285+ <item row="5" column="0" colspan="4">
4286+ <widget class="QCheckBox" name="checkBoxLighting">
4287+ <property name="text">
4288+ <string>Lighting (TODO: More clear name)</string>
4289+ </property>
4290+ </widget>
4291+ </item>
4292+ <item row="6" column="0" colspan="4">
4293+ <widget class="QCheckBox" name="checkBoxAtmosphere">
4294+ <property name="text">
4295+ <string>Atmosphere</string>
4296+ </property>
4297+ </widget>
4298+ </item>
4299+ <item row="7" column="0" colspan="4">
4300+ <widget class="QCheckBox" name="checkBoxHidden">
4301+ <property name="text">
4302+ <string>Hidden</string>
4303+ </property>
4304+ </widget>
4305+ </item>
4306+ <item row="8" column="0">
4307+ <widget class="QLabel" name="labelTexture">
4308+ <property name="text">
4309+ <string>Texture:</string>
4310+ </property>
4311+ </widget>
4312+ </item>
4313+ <item row="8" column="2">
4314+ <widget class="QLineEdit" name="lineEditTexture">
4315+ <property name="readOnly">
4316+ <bool>true</bool>
4317+ </property>
4318+ </widget>
4319+ </item>
4320+ <item row="8" column="3">
4321+ <widget class="QPushButton" name="pushButtonSelectTexture">
4322+ <property name="text">
4323+ <string>...</string>
4324+ </property>
4325+ </widget>
4326+ </item>
4327+ <item row="9" column="0" colspan="4">
4328+ <widget class="QFrame" name="frameMagnitude">
4329+ <layout class="QGridLayout" name="gridLayoutMagnitude">
4330+ <property name="margin">
4331+ <number>0</number>
4332+ </property>
4333+ <item row="1" column="0">
4334+ <widget class="QLabel" name="labelAbsoluteMagnitude">
4335+ <property name="text">
4336+ <string>Absolute magnitude:</string>
4337+ </property>
4338+ </widget>
4339+ </item>
4340+ <item row="1" column="1">
4341+ <widget class="QLineEdit" name="lineEditAbsoluteMagnitude"/>
4342+ </item>
4343+ <item row="1" column="2">
4344+ <widget class="QLabel" name="labelSlopeParameter">
4345+ <property name="text">
4346+ <string>Slope parameter:</string>
4347+ </property>
4348+ </widget>
4349+ </item>
4350+ <item row="1" column="3">
4351+ <widget class="QLineEdit" name="lineEditSlopeParameter"/>
4352+ </item>
4353+ <item row="2" column="0" colspan="4">
4354+ <widget class="QPushButton" name="pushButtonCalculateRadius">
4355+ <property name="text">
4356+ <string>Calculate the object's radius from the absolute magnitude and the current albedo</string>
4357+ </property>
4358+ </widget>
4359+ </item>
4360+ <item row="0" column="0" colspan="4">
4361+ <widget class="QLabel" name="labelMagnitudeSystem">
4362+ <property name="text">
4363+ <string>H-G two parameter magnitude system for minor planets:</string>
4364+ </property>
4365+ </widget>
4366+ </item>
4367+ </layout>
4368+ </widget>
4369+ </item>
4370+ <item row="4" column="2">
4371+ <widget class="QLineEdit" name="lineEditColor"/>
4372+ </item>
4373+ </layout>
4374+ </widget>
4375+ </item>
4376+ <item>
4377+ <widget class="QGroupBox" name="groupBoxOrbitalElements">
4378+ <property name="title">
4379+ <string>Orbital elements</string>
4380+ </property>
4381+ <layout class="QGridLayout" name="gridLayoutOrbitalElements">
4382+ <property name="margin">
4383+ <number>0</number>
4384+ </property>
4385+ <item row="0" column="0" colspan="2">
4386+ <widget class="QLabel" name="labelOrbitType">
4387+ <property name="text">
4388+ <string>Orbital function type:</string>
4389+ </property>
4390+ </widget>
4391+ </item>
4392+ <item row="1" column="0" colspan="2">
4393+ <widget class="QRadioButton" name="radioButtonCometaryOrbit">
4394+ <property name="text">
4395+ <string>Cometary orbit</string>
4396+ </property>
4397+ </widget>
4398+ </item>
4399+ <item row="2" column="0" colspan="2">
4400+ <widget class="QRadioButton" name="radioButtonEllipticOrbit">
4401+ <property name="text">
4402+ <string>Elliptic orbit</string>
4403+ </property>
4404+ </widget>
4405+ </item>
4406+ <item row="4" column="0">
4407+ <widget class="QLabel" name="labelEccentricity">
4408+ <property name="text">
4409+ <string>Eccentricity (%1):</string>
4410+ </property>
4411+ </widget>
4412+ </item>
4413+ <item row="4" column="1">
4414+ <widget class="QLineEdit" name="lineEditEccentricity">
4415+ <property name="text">
4416+ <string>0</string>
4417+ </property>
4418+ </widget>
4419+ </item>
4420+ <item row="5" column="0">
4421+ <widget class="QLabel" name="labelInclination">
4422+ <property name="text">
4423+ <string>Inclination (degrees):</string>
4424+ </property>
4425+ </widget>
4426+ </item>
4427+ <item row="5" column="1">
4428+ <widget class="QLineEdit" name="lineEditInclination"/>
4429+ </item>
4430+ <item row="6" column="0">
4431+ <widget class="QLabel" name="labelLongitudeOfTheAscendingNode">
4432+ <property name="text">
4433+ <string>Longitude of the ascending node %1:</string>
4434+ </property>
4435+ </widget>
4436+ </item>
4437+ <item row="6" column="1">
4438+ <widget class="QLineEdit" name="lineEditLongitudeOfTheAscendingNode"/>
4439+ </item>
4440+ <item row="7" column="0" colspan="2">
4441+ <widget class="QFrame" name="framePeriapsis">
4442+ <layout class="QGridLayout" name="gridLayoutPeriapsis">
4443+ <property name="margin">
4444+ <number>0</number>
4445+ </property>
4446+ <item row="0" column="0">
4447+ <widget class="QRadioButton" name="radioButtonArgumentOfPeriapsis">
4448+ <property name="text">
4449+ <string>Argument of the periapsis %1:</string>
4450+ </property>
4451+ </widget>
4452+ </item>
4453+ <item row="0" column="1">
4454+ <widget class="QLineEdit" name="lineEditArgumentOfPeriapsis"/>
4455+ </item>
4456+ <item row="1" column="0">
4457+ <widget class="QRadioButton" name="radioButtonLongitudeOfPeriapsis">
4458+ <property name="text">
4459+ <string>Longitude of the periapsis %1:</string>
4460+ </property>
4461+ </widget>
4462+ </item>
4463+ <item row="1" column="1">
4464+ <widget class="QLineEdit" name="lineEditLongitudeOfPeriapsis"/>
4465+ </item>
4466+ </layout>
4467+ </widget>
4468+ </item>
4469+ <item row="8" column="0" colspan="2">
4470+ <widget class="QFrame" name="frameSemiMajorAxis">
4471+ <layout class="QGridLayout" name="gridLayoutSemiMajorAxis">
4472+ <property name="margin">
4473+ <number>0</number>
4474+ </property>
4475+ <item row="0" column="1">
4476+ <widget class="QLineEdit" name="lineEditSemiMajorAxis"/>
4477+ </item>
4478+ <item row="1" column="1">
4479+ <widget class="QLineEdit" name="lineEditPeriapsisDistance"/>
4480+ </item>
4481+ <item row="0" column="0">
4482+ <widget class="QRadioButton" name="radioButtonSemiMajorAxis">
4483+ <property name="text">
4484+ <string>Semi-major axis %1:</string>
4485+ </property>
4486+ </widget>
4487+ </item>
4488+ <item row="1" column="0">
4489+ <widget class="QRadioButton" name="radioButtonPeriapsisDistance">
4490+ <property name="text">
4491+ <string>Periapsis distance %1:</string>
4492+ </property>
4493+ </widget>
4494+ </item>
4495+ </layout>
4496+ </widget>
4497+ </item>
4498+ <item row="9" column="0" colspan="2">
4499+ <widget class="QFrame" name="framePeriod">
4500+ <layout class="QGridLayout" name="gridLayoutPeriod">
4501+ <property name="margin">
4502+ <number>0</number>
4503+ </property>
4504+ <item row="0" column="0">
4505+ <widget class="QCheckBox" name="checkBoxPeriod">
4506+ <property name="text">
4507+ <string>Period:</string>
4508+ </property>
4509+ </widget>
4510+ </item>
4511+ <item row="0" column="1">
4512+ <widget class="QLineEdit" name="lineEditPeriod"/>
4513+ </item>
4514+ <item row="1" column="0">
4515+ <widget class="QCheckBox" name="checkBoxMeanMotion">
4516+ <property name="text">
4517+ <string>Mean motion:</string>
4518+ </property>
4519+ </widget>
4520+ </item>
4521+ <item row="1" column="1">
4522+ <widget class="QLineEdit" name="lineEditMeanMotion"/>
4523+ </item>
4524+ </layout>
4525+ </widget>
4526+ </item>
4527+ <item row="10" column="0" colspan="2">
4528+ <widget class="QFrame" name="frameEpoch">
4529+ <layout class="QGridLayout" name="gridLayoutEpoch">
4530+ <property name="margin">
4531+ <number>0</number>
4532+ </property>
4533+ <item row="0" column="1">
4534+ <widget class="QLineEdit" name="lineEditEpoch"/>
4535+ </item>
4536+ <item row="1" column="1" colspan="2">
4537+ <widget class="QLineEdit" name="lineEditTimeOfPeriapsis"/>
4538+ </item>
4539+ <item row="0" column="0">
4540+ <widget class="QRadioButton" name="radioButtonEpoch">
4541+ <property name="text">
4542+ <string>Epoch:</string>
4543+ </property>
4544+ </widget>
4545+ </item>
4546+ <item row="1" column="0">
4547+ <widget class="QRadioButton" name="radioButtonTimeOfPeriapsis">
4548+ <property name="text">
4549+ <string>Time of periapsis passage:</string>
4550+ </property>
4551+ </widget>
4552+ </item>
4553+ <item row="0" column="2">
4554+ <widget class="QPushButton" name="pushButtonEpochJ2000">
4555+ <property name="text">
4556+ <string>J2000.0</string>
4557+ </property>
4558+ </widget>
4559+ </item>
4560+ </layout>
4561+ </widget>
4562+ </item>
4563+ <item row="11" column="0" colspan="2">
4564+ <widget class="QFrame" name="frameMeanAnomaly">
4565+ <layout class="QGridLayout" name="gridLayout_2">
4566+ <property name="margin">
4567+ <number>0</number>
4568+ </property>
4569+ <item row="1" column="1">
4570+ <widget class="QLineEdit" name="lineEditMeanAnomaly"/>
4571+ </item>
4572+ <item row="2" column="1">
4573+ <widget class="QLineEdit" name="lineEditMeanLongitude"/>
4574+ </item>
4575+ <item row="1" column="0">
4576+ <widget class="QRadioButton" name="radioButtonMeanAnomaly">
4577+ <property name="text">
4578+ <string>Mean anomaly:</string>
4579+ </property>
4580+ </widget>
4581+ </item>
4582+ <item row="2" column="0">
4583+ <widget class="QRadioButton" name="radioButtonMeanLongitude">
4584+ <property name="text">
4585+ <string>Mean longitude:</string>
4586+ </property>
4587+ </widget>
4588+ </item>
4589+ </layout>
4590+ </widget>
4591+ </item>
4592+ <item row="3" column="0">
4593+ <widget class="QRadioButton" name="radioButtonOrbitFunction">
4594+ <property name="text">
4595+ <string>Object-specific:</string>
4596+ </property>
4597+ </widget>
4598+ </item>
4599+ <item row="3" column="1">
4600+ <widget class="QComboBox" name="comboBoxOrbitFunction"/>
4601+ </item>
4602+ <item row="12" column="0">
4603+ <widget class="QCheckBox" name="checkBoxOrbitVisualizationPeriod">
4604+ <property name="text">
4605+ <string>Orbit visualization period:</string>
4606+ </property>
4607+ </widget>
4608+ </item>
4609+ <item row="12" column="1">
4610+ <widget class="QLineEdit" name="lineEditOrbitVisualizationPeriod"/>
4611+ </item>
4612+ </layout>
4613+ </widget>
4614+ </item>
4615+ <item>
4616+ <widget class="QGroupBox" name="groupBoxRotationalElements">
4617+ <property name="title">
4618+ <string>Rotational elements</string>
4619+ </property>
4620+ <layout class="QGridLayout" name="gridLayout">
4621+ <item row="0" column="0">
4622+ <widget class="QCheckBox" name="checkBoxObliquity">
4623+ <property name="text">
4624+ <string>Obliquity:</string>
4625+ </property>
4626+ </widget>
4627+ </item>
4628+ <item row="0" column="1" colspan="3">
4629+ <widget class="QLineEdit" name="lineEditObliquity"/>
4630+ </item>
4631+ <item row="2" column="0">
4632+ <widget class="QCheckBox" name="checkBoxNorthPoleRA">
4633+ <property name="text">
4634+ <string>North pole right ascension:</string>
4635+ </property>
4636+ </widget>
4637+ </item>
4638+ <item row="2" column="1" colspan="3">
4639+ <widget class="QLineEdit" name="lineEditNorthPoleRA"/>
4640+ </item>
4641+ <item row="3" column="0">
4642+ <widget class="QCheckBox" name="checkBoxNorthPoleDec">
4643+ <property name="text">
4644+ <string>North pole declination:</string>
4645+ </property>
4646+ </widget>
4647+ </item>
4648+ <item row="3" column="1" colspan="3">
4649+ <widget class="QLineEdit" name="lineEditNorthPoleDec"/>
4650+ </item>
4651+ <item row="4" column="0">
4652+ <widget class="QCheckBox" name="checkBoxRotationalPeriod">
4653+ <property name="text">
4654+ <string>Period (hours):</string>
4655+ </property>
4656+ </widget>
4657+ </item>
4658+ <item row="4" column="1" colspan="3">
4659+ <widget class="QLineEdit" name="lineEditRotationalPeriod"/>
4660+ </item>
4661+ <item row="5" column="0">
4662+ <widget class="QCheckBox" name="checkBoxPrecessionRate">
4663+ <property name="text">
4664+ <string>Precession rate:</string>
4665+ </property>
4666+ </widget>
4667+ </item>
4668+ <item row="5" column="1" colspan="3">
4669+ <widget class="QLineEdit" name="lineEditPrecessionRate"/>
4670+ </item>
4671+ <item row="6" column="0">
4672+ <widget class="QCheckBox" name="checkBoxRotationalEpoch">
4673+ <property name="text">
4674+ <string>Epoch:</string>
4675+ </property>
4676+ </widget>
4677+ </item>
4678+ <item row="6" column="1">
4679+ <widget class="QLineEdit" name="lineEditRotationalEpoch"/>
4680+ </item>
4681+ <item row="7" column="0">
4682+ <widget class="QCheckBox" name="checkBoxOffset">
4683+ <property name="text">
4684+ <string>Offset:</string>
4685+ </property>
4686+ </widget>
4687+ </item>
4688+ <item row="7" column="1" colspan="3">
4689+ <widget class="QLineEdit" name="lineEditOffset"/>
4690+ </item>
4691+ <item row="1" column="0" colspan="3">
4692+ <widget class="QCheckBox" name="checkBoxEquatorAscendingNode">
4693+ <property name="text">
4694+ <string>Longitude of the ascending node of the ecliptic on the equator:</string>
4695+ </property>
4696+ </widget>
4697+ </item>
4698+ <item row="6" column="3">
4699+ <widget class="QPushButton" name="pushButtonRotationalEpochJ2000">
4700+ <property name="text">
4701+ <string>J2000.0</string>
4702+ </property>
4703+ </widget>
4704+ </item>
4705+ <item row="1" column="3">
4706+ <widget class="QLineEdit" name="lineEditEquatorAscendingNode"/>
4707+ </item>
4708+ </layout>
4709+ </widget>
4710+ </item>
4711+ <item>
4712+ <widget class="QGroupBox" name="groupBoxRings">
4713+ <property name="title">
4714+ <string>Rings</string>
4715+ </property>
4716+ <property name="checkable">
4717+ <bool>true</bool>
4718+ </property>
4719+ <property name="checked">
4720+ <bool>false</bool>
4721+ </property>
4722+ <layout class="QGridLayout" name="gridLayout_3">
4723+ <item row="0" column="0">
4724+ <widget class="QLabel" name="labelInnerSize">
4725+ <property name="text">
4726+ <string>Inner size:</string>
4727+ </property>
4728+ </widget>
4729+ </item>
4730+ <item row="1" column="0">
4731+ <widget class="QLabel" name="labelOuterSize">
4732+ <property name="text">
4733+ <string>Outer size:</string>
4734+ </property>
4735+ </widget>
4736+ </item>
4737+ <item row="2" column="0">
4738+ <widget class="QLabel" name="labelRingTexture">
4739+ <property name="text">
4740+ <string>Texture:</string>
4741+ </property>
4742+ </widget>
4743+ </item>
4744+ <item row="2" column="1">
4745+ <widget class="QLineEdit" name="lineEditRingTexture">
4746+ <property name="readOnly">
4747+ <bool>true</bool>
4748+ </property>
4749+ </widget>
4750+ </item>
4751+ <item row="2" column="2">
4752+ <widget class="QPushButton" name="pushButtonSelectRingTexture">
4753+ <property name="text">
4754+ <string>...</string>
4755+ </property>
4756+ </widget>
4757+ </item>
4758+ <item row="0" column="1" colspan="2">
4759+ <widget class="QLineEdit" name="lineEditRingInnerSize"/>
4760+ </item>
4761+ <item row="1" column="1" colspan="2">
4762+ <widget class="QLineEdit" name="lineEditRingOuterSize"/>
4763+ </item>
4764+ </layout>
4765+ </widget>
4766+ </item>
4767+ </layout>
4768+ </widget>
4769+ </widget>
4770+ </item>
4771+ <item row="3" column="0" colspan="2">
4772+ <widget class="QFrame" name="frameButton">
4773+ <layout class="QHBoxLayout" name="horizontalLayoutButton">
4774+ <item>
4775+ <widget class="QLabel" name="labelErrorMessage">
4776+ <property name="sizePolicy">
4777+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
4778+ <horstretch>0</horstretch>
4779+ <verstretch>0</verstretch>
4780+ </sizepolicy>
4781+ </property>
4782+ <property name="text">
4783+ <string/>
4784+ </property>
4785+ </widget>
4786+ </item>
4787+ <item>
4788+ <widget class="QPushButton" name="pushButtonSave">
4789+ <property name="text">
4790+ <string>Save</string>
4791+ </property>
4792+ </widget>
4793+ </item>
4794+ </layout>
4795+ </widget>
4796+ </item>
4797+ </layout>
4798+ </widget>
4799+ <customwidgets>
4800+ <customwidget>
4801+ <class>BarFrame</class>
4802+ <extends>QFrame</extends>
4803+ <header>Dialog.hpp</header>
4804+ <container>1</container>
4805+ </customwidget>
4806+ </customwidgets>
4807+ <tabstops>
4808+ <tabstop>lineEditName</tabstop>
4809+ <tabstop>lineEditIdentifier</tabstop>
4810+ <tabstop>checkBoxMinorPlanetNumber</tabstop>
4811+ <tabstop>lineEditMinorPlanetNumber</tabstop>
4812+ <tabstop>radioButtonSolarSystemObject</tabstop>
4813+ <tabstop>radioButtonMinorPlanet</tabstop>
4814+ <tabstop>radioButtonComet</tabstop>
4815+ <tabstop>radioButtonSatellite</tabstop>
4816+ <tabstop>scrollArea</tabstop>
4817+ <tabstop>comboBoxParent</tabstop>
4818+ <tabstop>lineEditRadius</tabstop>
4819+ <tabstop>lineEditOblateness</tabstop>
4820+ <tabstop>lineEditAlbedo</tabstop>
4821+ <tabstop>lineEditColor</tabstop>
4822+ <tabstop>pushButtonSelectColor</tabstop>
4823+ <tabstop>checkBoxLighting</tabstop>
4824+ <tabstop>checkBoxAtmosphere</tabstop>
4825+ <tabstop>checkBoxHidden</tabstop>
4826+ <tabstop>lineEditTexture</tabstop>
4827+ <tabstop>pushButtonSelectTexture</tabstop>
4828+ <tabstop>lineEditAbsoluteMagnitude</tabstop>
4829+ <tabstop>lineEditSlopeParameter</tabstop>
4830+ <tabstop>pushButtonCalculateRadius</tabstop>
4831+ <tabstop>radioButtonCometaryOrbit</tabstop>
4832+ <tabstop>radioButtonEllipticOrbit</tabstop>
4833+ <tabstop>radioButtonOrbitFunction</tabstop>
4834+ <tabstop>comboBoxOrbitFunction</tabstop>
4835+ <tabstop>lineEditEccentricity</tabstop>
4836+ <tabstop>lineEditInclination</tabstop>
4837+ <tabstop>lineEditLongitudeOfTheAscendingNode</tabstop>
4838+ <tabstop>radioButtonArgumentOfPeriapsis</tabstop>
4839+ <tabstop>lineEditArgumentOfPeriapsis</tabstop>
4840+ <tabstop>radioButtonLongitudeOfPeriapsis</tabstop>
4841+ <tabstop>lineEditLongitudeOfPeriapsis</tabstop>
4842+ <tabstop>radioButtonSemiMajorAxis</tabstop>
4843+ <tabstop>lineEditSemiMajorAxis</tabstop>
4844+ <tabstop>radioButtonPeriapsisDistance</tabstop>
4845+ <tabstop>lineEditPeriapsisDistance</tabstop>
4846+ <tabstop>checkBoxPeriod</tabstop>
4847+ <tabstop>lineEditPeriod</tabstop>
4848+ <tabstop>checkBoxMeanMotion</tabstop>
4849+ <tabstop>lineEditMeanMotion</tabstop>
4850+ <tabstop>radioButtonEpoch</tabstop>
4851+ <tabstop>lineEditEpoch</tabstop>
4852+ <tabstop>pushButtonEpochJ2000</tabstop>
4853+ <tabstop>radioButtonTimeOfPeriapsis</tabstop>
4854+ <tabstop>lineEditTimeOfPeriapsis</tabstop>
4855+ <tabstop>radioButtonMeanAnomaly</tabstop>
4856+ <tabstop>lineEditMeanAnomaly</tabstop>
4857+ <tabstop>radioButtonMeanLongitude</tabstop>
4858+ <tabstop>lineEditMeanLongitude</tabstop>
4859+ <tabstop>checkBoxOrbitVisualizationPeriod</tabstop>
4860+ <tabstop>lineEditOrbitVisualizationPeriod</tabstop>
4861+ <tabstop>checkBoxObliquity</tabstop>
4862+ <tabstop>lineEditObliquity</tabstop>
4863+ <tabstop>checkBoxEquatorAscendingNode</tabstop>
4864+ <tabstop>lineEditEquatorAscendingNode</tabstop>
4865+ <tabstop>checkBoxNorthPoleRA</tabstop>
4866+ <tabstop>lineEditNorthPoleRA</tabstop>
4867+ <tabstop>checkBoxNorthPoleDec</tabstop>
4868+ <tabstop>lineEditNorthPoleDec</tabstop>
4869+ <tabstop>checkBoxRotationalPeriod</tabstop>
4870+ <tabstop>lineEditRotationalPeriod</tabstop>
4871+ <tabstop>checkBoxPrecessionRate</tabstop>
4872+ <tabstop>lineEditPrecessionRate</tabstop>
4873+ <tabstop>checkBoxRotationalEpoch</tabstop>
4874+ <tabstop>lineEditRotationalEpoch</tabstop>
4875+ <tabstop>pushButtonRotationalEpochJ2000</tabstop>
4876+ <tabstop>checkBoxOffset</tabstop>
4877+ <tabstop>lineEditOffset</tabstop>
4878+ <tabstop>groupBoxRings</tabstop>
4879+ <tabstop>lineEditRingInnerSize</tabstop>
4880+ <tabstop>lineEditRingOuterSize</tabstop>
4881+ <tabstop>lineEditRingTexture</tabstop>
4882+ <tabstop>pushButtonSelectRingTexture</tabstop>
4883+ <tabstop>pushButtonSave</tabstop>
4884+ </tabstops>
4885+ <resources/>
4886+ <connections/>
4887+</ui>
4888
4889=== added file 'plugins/SolarSystemEditor/src/gui/mpcImportWindow.ui'
4890--- plugins/SolarSystemEditor/src/gui/mpcImportWindow.ui 1970-01-01 00:00:00 +0000
4891+++ plugins/SolarSystemEditor/src/gui/mpcImportWindow.ui 2010-11-16 20:06:17 +0000
4892@@ -0,0 +1,679 @@
4893+<?xml version="1.0" encoding="UTF-8"?>
4894+<ui version="4.0">
4895+ <author>Bogdan Marinov</author>
4896+ <class>mpcImportWindow</class>
4897+ <widget class="QWidget" name="mpcImportWindow">
4898+ <property name="geometry">
4899+ <rect>
4900+ <x>0</x>
4901+ <y>0</y>
4902+ <width>480</width>
4903+ <height>475</height>
4904+ </rect>
4905+ </property>
4906+ <layout class="QVBoxLayout" name="verticalLayout_2">
4907+ <property name="spacing">
4908+ <number>0</number>
4909+ </property>
4910+ <property name="margin">
4911+ <number>0</number>
4912+ </property>
4913+ <item>
4914+ <widget class="BarFrame" name="TitleBar">
4915+ <property name="sizePolicy">
4916+ <sizepolicy hsizetype="Expanding" vsizetype="Minimum">
4917+ <horstretch>0</horstretch>
4918+ <verstretch>0</verstretch>
4919+ </sizepolicy>
4920+ </property>
4921+ <property name="minimumSize">
4922+ <size>
4923+ <width>0</width>
4924+ <height>25</height>
4925+ </size>
4926+ </property>
4927+ <property name="maximumSize">
4928+ <size>
4929+ <width>16777215</width>
4930+ <height>30</height>
4931+ </size>
4932+ </property>
4933+ <property name="focusPolicy">
4934+ <enum>Qt::NoFocus</enum>
4935+ </property>
4936+ <property name="autoFillBackground">
4937+ <bool>false</bool>
4938+ </property>
4939+ <property name="frameShape">
4940+ <enum>QFrame::StyledPanel</enum>
4941+ </property>
4942+ <layout class="QHBoxLayout" name="_2">
4943+ <property name="spacing">
4944+ <number>6</number>
4945+ </property>
4946+ <property name="leftMargin">
4947+ <number>0</number>
4948+ </property>
4949+ <property name="topMargin">
4950+ <number>0</number>
4951+ </property>
4952+ <property name="rightMargin">
4953+ <number>4</number>
4954+ </property>
4955+ <property name="bottomMargin">
4956+ <number>0</number>
4957+ </property>
4958+ <item>
4959+ <spacer name="leftSpacer">
4960+ <property name="orientation">
4961+ <enum>Qt::Horizontal</enum>
4962+ </property>
4963+ <property name="sizeHint" stdset="0">
4964+ <size>
4965+ <width>40</width>
4966+ <height>20</height>
4967+ </size>
4968+ </property>
4969+ </spacer>
4970+ </item>
4971+ <item>
4972+ <widget class="QLabel" name="stelWindowTitle">
4973+ <property name="text">
4974+ <string notr="true" extracomment="The title of the window will be set during runtime">Import data</string>
4975+ </property>
4976+ </widget>
4977+ </item>
4978+ <item>
4979+ <spacer name="rightSpacer">
4980+ <property name="orientation">
4981+ <enum>Qt::Horizontal</enum>
4982+ </property>
4983+ <property name="sizeHint" stdset="0">
4984+ <size>
4985+ <width>40</width>
4986+ <height>20</height>
4987+ </size>
4988+ </property>
4989+ </spacer>
4990+ </item>
4991+ <item>
4992+ <widget class="QPushButton" name="closeStelWindow">
4993+ <property name="minimumSize">
4994+ <size>
4995+ <width>16</width>
4996+ <height>16</height>
4997+ </size>
4998+ </property>
4999+ <property name="maximumSize">
5000+ <size>
The diff has been truncated for viewing.