Kstars

LocationEdit.qml
1// SPDX-FileCopyrightText: 2016 Artem Fedoskin <afedoskin3@gmail.com>
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4import QtQuick.Controls 2.0
5import QtQuick 2.7
6import QtQuick.Layouts 1.1
7import "../../constants" 1.0
8import "../../modules"
9import QtPositioning 5.2
10
11KSPage {
12 id: locationEdit
13 title: editMode ? xi18n("Edit location") : (isReadOnly ? xi18n("View location") : xi18n("Add location"))
14 property bool editMode: false
15 property bool isAvailable: positionSource.valid
16 property bool isReadOnly: false
17 property string geoName
18 property bool fieldsChanged: false //true whenever either city, province or country fields are changed. Turned to false every time this page is opened
19 property string loadingText //Text used in location loading popup
20 property string fetchingCoordinatesLoading: xi18n("Please, wait while we are fetching coordinates")
21
22 property bool fetchingName: false // true when we are fetchingN name of location
23 property bool addAutomatically: false //true if user wants add location automatically without manually editing the fields
24
25 signal locationFetched(var _lat, var _lng) //emitted when location is fetched in auto mode
26 signal locNameFetched(var _city, var _region, var _country) //emitted when location nane is fetched or was failed to fetch in auto mode
27
28 /*This function sets coordinates from GPS automatically, without asking user to fill information
29 about location */
30 function setAutomaticallyFromGPS() {
31 addAutomatically = true
32 positionSource.stop()
33 positionSource.start()
34 loadingText = fetchingCoordinatesLoading
35 if(!positionSource.valid) {
36 positionSource.stop()
37 skyMapLite.notification.showNotification(xi18("Positioning is not available on your device"))
38 }
39 }
40
41 property double lat
42 property double lng
43 property string city
44 property string region
45 property string country
46 property int tz
47
48 onLocationFetched: {
49 lat = _lat
50 lng = _lng
51 }
52
53 Timer {
54 id: nameFetchTimeout
55 interval: 20000;
56 onTriggered: {
57 locationLoading.close()
58 var city = xi18n("Default city")
59 var province = xi18n("Default province")
60 var country = xi18n("Default country")
61 if(addAutomatically) {
62 skyMapLite.notification.showNotification(xi18n("Could not fetch location name (check your Internet connection). Added with default name"))
63 if(!LocationDialogLite.addCity(city, province, country,
64 lat, lng, tz,
65 "--")) {
66 skyMapLite.notification.showNotification(xi18n("Failed to set location"))
67 return
68 }
69
70 if(LocationDialogLite.setLocation(city + ", " + province + ", " + country)) {
71 skyMapLite.notification.showNotification(xi18n("Successfully set your location"))
72 } else {
73 skyMapLite.notification.showNotification(xi18n("Could not set your location"))
74 }
75 } else {
76 skyMapLite.notification.showNotification(xi18n("Could not fetch location name (check your Internet connection). Set default name"))
77 cityField.text = city
78 provinceField.text = province
79 countryField.text = country
80 comboBoxTZ.currentIndex = comboBoxTZ.find(tz)
81 }
82 fetchingName = false
83 addAutomatically = false
84 }
85 }
86
87 onLocNameFetched: {
88 nameFetchTimeout.running = false
89 city = _city
90 region = _region
91 country = _country
92
93 if(!LocationDialogLite.addCity(city, region, country,
94 lat, lng, tz,
95 "--")) {
96 skyMapLite.notification.showNotification(xi18n("Failed to set location"))
97 }
98
99 if(LocationDialogLite.setLocation(city + ", " + region + ", " + country)) {
100 skyMapLite.notification.showNotification(xi18n("Successfully set your location"))
101 } else {
102 skyMapLite.notification.showNotification(xi18n("Could not set your location"))
103 }
104
105 addAutomatically = false
106 }
107
108 function openAdd() {
109 editMode = false
110 isReadOnly = false
111 stackView.push(this)
112 fieldsChanged = false
113 }
114
115 function openEdit(fullName, readOnly) {
116 geoName = fullName
117 isReadOnly = readOnly
118
119 if(!readOnly) {
120 editMode = true
121 }
122
123 cityField.text = LocationDialogLite.getCity(fullName)
124 provinceField.text = LocationDialogLite.getProvince(fullName)
125 countryField.text = LocationDialogLite.getCountry(fullName)
126
127 latField.text = LocationDialogLite.getLatitude(fullName)
128 longField.text = LocationDialogLite.getLongitude(fullName)
129
130 comboBoxTZ.currentIndex = LocationDialogLite.getTZ(fullName)
131 comboBoxDST.currentIndex = LocationDialogLite.getDST(fullName)
132 stackView.push(this)
133 fieldsChanged = false
134 }
135
136 PositionSource {
137 id: positionSource
138
139 property bool error: false
140
141 onSourceErrorChanged: {
142 if (sourceError == PositionSource.NoError)
143 return
144
145 var errorDesc = ""
146
147 if (sourceError == 2 || sourceError == 1) {
148 errorDesc = xi18n("No location service (GPS, cellular service, etc.) is available.\nPlease, switch on the location service, and retry")
149 } else if (sourceError == 4) {
150 errorDesc = xi18n("Unknown error occurred. Please contact the application developer.")
151 }
152
153 skyMapLite.notification.showNotification(errorDesc)
154 positionSource.stop()
155 error = true
156 locationLoading.close()
157 }
158
159 onUpdateTimeout: {
160 skyMapLite.notification.showNotification(xi18n("Timeout occurred. Try again."))
161 locationLoading.close()
162 }
163
164 onActiveChanged: {
165 if(positionSource.active && !error) {
166 locationLoading.open()
167 } else if (!fetchingName) {
168 locationLoading.close()
169 error = false
170 }
171 }
172
173 onPositionChanged: {
174 if(isLoaded) {
175 skyMapLite.notification.showNotification(xi18n("Found your longitude and altitude"))
176 var lat = positionSource.position.coordinate.latitude
177 var lng = positionSource.position.coordinate.longitude
178 latField.text = lat
179 longField.text = lng
180 if(addAutomatically) {
181 locationFetched(lat, lng)
182 }
183
184 tz = (new Date().getTimezoneOffset()/60)*-1
185 loadingText = xi18n("Please, wait while we are retrieving location name")
186 fetchingName = true // must be set to true before we are stopping positioning service
187 positionSource.stop()
189 nameFetchTimeout.running = true
190 setTZComboBox(new Date().getTimezoneOffset())
191 }
192 }
193 preferredPositioningMethods: PositionSource.AllPositioningMethods
194 }
195
196 function setTZComboBox(TZMinutes) {
197 var TZ = (TZMinutes/60)*-1
198 comboBoxTZ.currentIndex = comboBoxTZ.find(TZ)
199 }
200
201 Connections {
202 target: LocationDialogLite
203 onNewNameFromCoordinates: {
204 if(addAutomatically) {
205 locNameFetched(city, region, country)
206 }
207 cityField.text = city
208 provinceField.text = region
209 countryField.text = country
210 fetchingName = false
211 locationLoading.close()
212 addAutomatically = false
213 }
214 }
215
216 //close the popup and clears all text fields
217 onVisibleChanged: {
218 if(!visible) {
219 cityField.clear()
220 provinceField.clear()
221 countryField.clear()
222 latField.clear()
223 longField.clear()
224 }
225 }
226
227 ColumnLayout {
228 anchors {
229 left: parent.left
230 right: parent.right
231 }
232
233 GridLayout {
234 anchors {
235 left: parent.left
236 right: parent.right
237 }
238
239 flow: window.isPortrait ? GridLayout.TopToBottom : GridLayout.LeftToRight
240
241 ColumnLayout {
242 anchors.top: parent.top
243 Layout.maximumWidth: window.isPortrait ? parent.width : parent.width/2
244
245 RowLayout {
246 KSLabel {
247 text: xi18n("City: ")
248 }
249
250 KSTextField {
251 id: cityField
252 Layout.fillWidth: true
253 onTextChanged: fieldsChanged = true
254 readOnly: isReadOnly
255 }
256 }
257
258 RowLayout {
259 KSLabel {
260 text: xi18n("Province: ")
261 }
262
263 KSTextField {
264 id: provinceField
265 Layout.fillWidth: true
266 onTextChanged: fieldsChanged = true
267 readOnly: isReadOnly
268 }
269 }
270
271 RowLayout {
272 KSLabel {
273 text: xi18n("Country: ")
274 }
275
276 KSTextField {
277 id: countryField
278 Layout.fillWidth: true
279 onTextChanged: fieldsChanged = true
280 readOnly: isReadOnly
281 }
282 }
283 }
284
285 Item {
286 height: window.isPortrait ? 15 : 0
287 }
288
289 ColumnLayout {
290 Layout.maximumWidth: window.isPortrait ? parent.width : parent.width/2
291
292 RowLayout {
293 KSLabel {
294 text: xi18n("Latitude: ")
295 }
296
297 KSTextField {
298 id: latField
299 Layout.fillWidth: true
300 readOnly: isReadOnly
301 }
302 }
303
304 RowLayout {
305
306 KSLabel {
307 text: xi18n("Longitude: ")
308 }
309
310 KSTextField {
311 id: longField
312 Layout.fillWidth: true
313 readOnly: isReadOnly
314 }
315 }
316
317 Flow {
318 Layout.fillWidth: true
319 spacing: 10
320
321 RowLayout {
322 KSLabel {
323 text: xi18n("UT offset: ")
324 }
325
326 ComboBox {
327 id: comboBoxTZ
328 model: LocationDialogLite.TZList
329 }
330 }
331
332 RowLayout {
333 KSLabel {
334 text: xi18n("DST rule: ")
335 }
336
337 ComboBox {
338 id: comboBoxDST
339 model: LocationDialogLite.DSTRules
340 }
341 }
342 }
343 }
344 }
345
346 Flow {
347 Layout.fillWidth: true
348 spacing: 10
349
350 Button {
351 visible: !isReadOnly
352 text: xi18n("Set from GPS")
353 enabled: isAvailable
354 onClicked: {
355 positionSource.stop()
356 positionSource.start()
357 loadingText = fetchingCoordinatesLoading
358 if(!positionSource.valid) {
359 positionSource.stop()
360 skyMapLite.notification.showNotification(xi18("Positioning is not available on your device"))
361 }
362 }
363
364 Connections {
365 target: locationLoading
366 onClosed: {
367 positionSource.stop()
368 }
369 }
370 }
371
372 Button {
373 //enabled:
374 visible: !isReadOnly
375 text: editMode ? xi18n("Save") : xi18n("Add")
376 onClicked: {
377 if(cityField.text == "") {
378 skyMapLite.notification.showNotification(xi18n("Please, fill in the city"))
379 return
380 } else if(countryField.text == "") {
381 skyMapLite.notification.showNotification(xi18n("Please, fill in the country"))
382 return
383 } else if(latField.text == "") {
384 skyMapLite.notification.showNotification(xi18n("Please, fill in the latitude"))
385 return
386 } else if(longField.text == "") {
387 skyMapLite.notification.showNotification(xi18n("Please, fill in the longitude"))
388 return
389 }
390
391 if(!LocationDialogLite.checkLongLat(longField.text, latField.text)) {
392 skyMapLite.notification.showNotification(xi18n("Either the longitude or the latitude values are not valid"))
393 return
394 }
395
396 if(fieldsChanged) {
397 if(LocationDialogLite.isDuplicate(cityField.text, provinceField.text, countryField.text)) {
398 skyMapLite.notification.showNotification(xi18n("This location already exists. Change either the city, the province or the country"))
399 return
400 }
401 }
402
403 //Fullname of new location
404 var fullName = cityField.text + ", "
405 if(provinceField.text != "") {
406 fullName += provinceField.text + ", "
407 }
408 fullName += countryField.text
409
410 if(!editMode) {
411 if(!LocationDialogLite.addCity(cityField.text, provinceField.text, countryField.text,
412 latField.text, longField.text, comboBoxTZ.currentText,
413 comboBoxDST.currentText)) {
414 skyMapLite.notification.showNotification(xi18n("Failed to add location"))
415 return
416 } else {
417 skyMapLite.notification.showNotification(xi18n("Added new location - %1", fullName))
418 }
419 } else {
420 if(!LocationDialogLite.editCity(geoName, cityField.text, provinceField.text, countryField.text,
421 latField.text, longField.text, comboBoxTZ.currentText,
422 comboBoxDST.currentText)) {
423 skyMapLite.notification.showNotification(xi18n("Failed to edit city"))
424 return
425 }
426 }
427
428 locationDialog.filterCities()
429 if(!editMode) {
430 //If we are adding location then open menu with newly added location
431 locationsGeoMenu.openMenu(fullName)
432 }
433
434 stackView.pop()
435 }
436 }
437
438 Button {
439 text: xi18n("Cancel")
440 onClicked: {
441 stackView.pop()
442 }
443 }
444 }
445 }
446}
A backend of location dialog declared in QML.
Q_INVOKABLE bool checkLongLat(const QString &longitude, const QString &latitude)
checkLongLat checks whether given longitude and latitude are valid
Q_INVOKABLE void getNameFromCoordinates(double latitude, double longitude)
Retrieve name of location by latitude and longitude.
QString xi18n(const char *text, const TYPE &arg...)
QString fullName(const PartType &type)
QWidget * window(QObject *job)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
QStringView country(QStringView ifopt)
QTextStream & left(QTextStream &stream)
QTextStream & right(QTextStream &stream)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 4 2024 16:38:43 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.