1 /*
2 Gpredict: Real-time satellite tracking and orbit prediction program
3
4 Copyright (C) 2001-2017 Alexandru Csete, OZ9AEC
5 2011 Charles Suprin, AA1VS
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, visit http://www.fsf.org/
19 */
20
21 /*
22 * Edit ground station details.
23 *
24 * The functions in this unit are used to edit the details of a given
25 * ground station. The editor consists of a simple dialog window containing
26 * widget for the individual setting.
27 *
28 * The functions can be used for editing the details of an existing ground
29 * station or for adding a new location. In the first case, the widgets
30 * in dialog will be preloaded with the existing data, while in the second
31 * case the widgets will be empty and, upon successful completion a new
32 * entry will be added to the GtkTreeView which contains the locations.
33 */
34
35 #ifdef HAVE_CONFIG_H
36 #include <build-config.h>
37 #endif
38 #include <glib/gi18n.h>
39 #include <glib/gstdio.h>
40 #include <gtk/gtk.h>
41 #include <math.h>
42
43 #include "gpredict-utils.h"
44 #include "loc-tree.h"
45 #include "locator.h"
46 #include "sat-cfg.h"
47 #include "sat-log.h"
48 #include "sat-pref-qth-data.h"
49 #include "sat-pref-qth-editor.h"
50
51 /*
52 * Symbolic refs to be used when calling select_location in order
53 * to determine which mode the selection should run in, ie.
54 * select location or select weather station.
55 */
56 enum {
57 SELECTION_MODE_LOC = 1,
58 SELECTION_MODE_WX = 2
59 };
60
61 extern GtkWidget *window; /* dialog window defined in sat-pref.c */
62
63 static GtkWidget *dialog; /* dialog window */
64 static GtkWidget *name; /* QTH name */
65 static GtkWidget *location; /* QTH location */
66 static GtkWidget *desc; /* QTH description */
67 static GtkWidget *lat, *lon, *alt; /* LAT, LON and ALT */
68 static GtkWidget *ns, *ew;
69 static GtkWidget *qra; /* QRA locator */
70 static gulong latsigid, lonsigid, nssigid, ewsigid, qrasigid;
71 static GtkWidget *wx; /* weather station */
72
73 #ifdef HAS_LIBGPS
74 static GtkWidget *type; /* GPSD type */
75 static GtkWidget *server; /* GPSD Server */
76 static GtkWidget *port; /* GPSD Port */
77 #endif
78
79
80 /* Update widgets from the currently selected row in the treeview */
update_widgets(GtkTreeView * treeview)81 static void update_widgets(GtkTreeView * treeview)
82 {
83 GtkTreeSelection *selection; /* the selection in the tree view */
84 GtkTreeModel *model; /* the tree model corresponding to the selection */
85 GtkTreeIter iter; /* the iter of the selection */
86 gchar *qthname; /* location name */
87 gchar *qthdesc; /* location description */
88 gchar *qthloc; /* location */
89 gdouble qthlat; /* latitude */
90 gdouble qthlon; /* longitude */
91 guint qthalt; /* altitude */
92 gchar *qthwx; /* weather station */
93 gchar *qthgpsdserver; /* gpsdserver */
94 guint qthtype; /* type */
95 guint qthgpsdport; /* gpsdport */
96
97 selection = gtk_tree_view_get_selection(treeview);
98 if (gtk_tree_selection_get_selected(selection, &model, &iter))
99 {
100 /* get values */
101 gtk_tree_model_get(model, &iter,
102 QTH_LIST_COL_NAME, &qthname,
103 QTH_LIST_COL_LOC, &qthloc,
104 QTH_LIST_COL_DESC, &qthdesc,
105 QTH_LIST_COL_LAT, &qthlat,
106 QTH_LIST_COL_LON, &qthlon,
107 QTH_LIST_COL_ALT, &qthalt,
108 QTH_LIST_COL_WX, &qthwx,
109 QTH_LIST_COL_GPSD_SERVER, &qthgpsdserver,
110 QTH_LIST_COL_GPSD_PORT, &qthgpsdport,
111 QTH_LIST_COL_TYPE, &qthtype, -1);
112
113 /* update widgets and free memory afterwards */
114 if (qthname)
115 {
116 gtk_entry_set_text(GTK_ENTRY(name), qthname);
117 }
118
119 if (qthloc)
120 {
121 gtk_entry_set_text(GTK_ENTRY(location), qthloc);
122 g_free(qthloc);
123 }
124
125 if (qthdesc)
126 {
127 gtk_entry_set_text(GTK_ENTRY(desc), qthdesc);
128 g_free(qthdesc);
129 }
130
131 if (qthwx)
132 {
133 gtk_entry_set_text(GTK_ENTRY(wx), qthwx);
134 g_free(qthwx);
135 }
136 #ifdef HAS_LIBGPS
137 if (qthgpsdserver)
138 {
139 gtk_entry_set_text(GTK_ENTRY(server), qthgpsdserver);
140 g_free(qthgpsdserver);
141 }
142 #endif
143 if (qthlat < 0.00)
144 gtk_combo_box_set_active(GTK_COMBO_BOX(ns), 1);
145 else
146 gtk_combo_box_set_active(GTK_COMBO_BOX(ns), 0);
147
148 gtk_spin_button_set_value(GTK_SPIN_BUTTON(lat), fabs(qthlat));
149
150 if (qthlon < 0.00)
151 gtk_combo_box_set_active(GTK_COMBO_BOX(ew), 1);
152 else
153 gtk_combo_box_set_active(GTK_COMBO_BOX(ew), 0);
154
155 gtk_spin_button_set_value(GTK_SPIN_BUTTON(lon), fabs(qthlon));
156
157 gtk_spin_button_set_value(GTK_SPIN_BUTTON(alt), qthalt);
158 #ifdef HAS_LIBGPS
159 gtk_spin_button_set_value(GTK_SPIN_BUTTON(port), qthgpsdport);
160 gtk_combo_box_set_active(GTK_COMBO_BOX(type), qthtype);
161 #endif
162
163 sat_log_log(SAT_LOG_LEVEL_DEBUG,
164 _("%s:%d: Loaded %s for editing:\n"
165 "LAT:%.4f LON:%.4f ALT:%d"),
166 __FILE__, __LINE__,
167 (qthname != NULL) ? qthname : "???",
168 qthlat, qthlon, qthalt);
169
170 g_free(qthname);
171
172 }
173 else
174 {
175 sat_log_log(SAT_LOG_LEVEL_ERROR,
176 _("%s:%d: No ground station selected!"),
177 __FILE__, __LINE__);
178 }
179 }
180
181 /**
182 * Clear the contents of all widgets.
183 *
184 * This function is usually called when the user clicks on the CLEAR button
185 *
186 */
clear_widgets()187 static void clear_widgets()
188 {
189 gtk_entry_set_text(GTK_ENTRY(name), "");
190 gtk_entry_set_text(GTK_ENTRY(location), "");
191 gtk_entry_set_text(GTK_ENTRY(desc), "");
192 gtk_entry_set_text(GTK_ENTRY(wx), "");
193 gtk_spin_button_set_value(GTK_SPIN_BUTTON(lat), 0.0);
194 gtk_spin_button_set_value(GTK_SPIN_BUTTON(lon), 0.0);
195 gtk_spin_button_set_value(GTK_SPIN_BUTTON(alt), 0);
196 gtk_entry_set_text(GTK_ENTRY(qra), "");
197 }
198
199 /**
200 * Apply changes.
201 * @return TRUE if things are ok, FALSE otherwise.
202 *
203 * This function is usually called when the user clicks the OK button.
204 */
apply_changes(GtkTreeView * treeview,gboolean new)205 static gboolean apply_changes(GtkTreeView * treeview, gboolean new)
206 {
207 GtkTreeSelection *selection; /* selection in the treeview */
208 GtkTreeModel *model; /* the tree model corresponding to the selection */
209 GtkListStore *liststore; /* the list store corresponding to the model */
210 GtkTreeIter iter; /* iter used to add and modify row data */
211 const gchar *qthname;
212 const gchar *qthloc;
213 const gchar *qthdesc;
214 const gchar *qthwx;
215 const gchar *qthgpsdserver;
216 gdouble qthlat;
217 gdouble qthlon;
218 guint qthalt;
219 guint qthtype;
220 guint qthgpsdport;
221 const gchar *qthqra;
222
223 /* get values from dialog box */
224 qthname = gtk_entry_get_text(GTK_ENTRY(name));
225 qthloc = gtk_entry_get_text(GTK_ENTRY(location));
226 qthdesc = gtk_entry_get_text(GTK_ENTRY(desc));
227 qthwx = gtk_entry_get_text(GTK_ENTRY(wx));
228
229 #ifdef HAS_LIBGPS
230 qthgpsdserver = gtk_entry_get_text(GTK_ENTRY(server));
231 #else
232 qthgpsdserver = "";
233 #endif
234
235 qthlat = gtk_spin_button_get_value(GTK_SPIN_BUTTON(lat));
236 if (gtk_combo_box_get_active(GTK_COMBO_BOX(ns)))
237 qthlat = -qthlat;
238
239 qthlon = gtk_spin_button_get_value(GTK_SPIN_BUTTON(lon));
240 if (gtk_combo_box_get_active(GTK_COMBO_BOX(ew)))
241 qthlon = -qthlon;
242
243 qthalt = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(alt));
244
245 #ifdef HAS_LIBGPS
246 qthgpsdport = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(port));
247 qthtype = gtk_combo_box_get_active(GTK_COMBO_BOX(type));
248 #else
249 qthgpsdport = 0;
250 qthtype = 0; // FIXME: should probably use a #define
251 #endif
252
253 /* get liststore */
254 liststore = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
255
256 /* if this is a new entry, insert row into model */
257 if (new == TRUE)
258 {
259 gtk_list_store_append(liststore, &iter);
260 }
261 /* otherwise get current selection */
262 else
263 {
264 selection = gtk_tree_view_get_selection(treeview);
265
266 if (gtk_tree_selection_get_selected(selection, &model, &iter))
267 {
268 liststore = GTK_LIST_STORE(model);
269 }
270 else
271 {
272 /* no selection; internal error */
273 sat_log_log(SAT_LOG_LEVEL_ERROR,
274 _("%s:%d: Oooops, gpredict encountered an internal "
275 "error (no selection in qth list)"), __FILE__,
276 __LINE__);
277
278 return FALSE;
279 }
280 }
281
282 /* update values */
283 gtk_list_store_set(liststore, &iter,
284 QTH_LIST_COL_NAME, qthname,
285 QTH_LIST_COL_LOC, qthloc,
286 QTH_LIST_COL_DESC, qthdesc,
287 QTH_LIST_COL_LAT, qthlat,
288 QTH_LIST_COL_LON, qthlon,
289 QTH_LIST_COL_ALT, qthalt,
290 QTH_LIST_COL_WX, qthwx,
291 QTH_LIST_COL_GPSD_SERVER, qthgpsdserver,
292 QTH_LIST_COL_GPSD_PORT, qthgpsdport,
293 QTH_LIST_COL_TYPE, qthtype, -1);
294
295 qthqra = gtk_entry_get_text(GTK_ENTRY(qra));
296 gtk_list_store_set(liststore, &iter, QTH_LIST_COL_QRA, qthqra, -1);
297
298 return TRUE;
299 }
300
301 /**
302 * Manage name changes.
303 *
304 * This function is called when the contents of the name entry changes.
305 * The primary purpose of this function is to check whether the char length
306 * of the name is greater than zero, if yes enable the OK button of the dialog.
307 */
name_changed(GtkWidget * widget,gpointer data)308 static void name_changed(GtkWidget * widget, gpointer data)
309 {
310 const gchar *text;
311 gchar *entry, *end, *j;
312 gint len, pos;
313
314 (void)data; /* avoid unused parameter compiler warning */
315
316 /* step 1: ensure that only valid characters are entered
317 (stolen from xlog, tnx pg4i)
318 */
319 entry = gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1);
320 if ((len = g_utf8_strlen(entry, -1)) > 0)
321 {
322 end = entry + g_utf8_strlen(entry, -1);
323 for (j = entry; j < end; ++j)
324 {
325 if (!gpredict_legal_char(*j))
326 {
327 gdk_beep();
328 pos = gtk_editable_get_position(GTK_EDITABLE(widget));
329 gtk_editable_delete_text(GTK_EDITABLE(widget), pos, pos + 1);
330 }
331 }
332 }
333
334 /* step 2: if name seems all right, enable OK button */
335 text = gtk_entry_get_text(GTK_ENTRY(widget));
336
337 if (g_utf8_strlen(text, -1) > 0)
338 {
339 gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog),
340 GTK_RESPONSE_OK, TRUE);
341 }
342 else
343 {
344 gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog),
345 GTK_RESPONSE_OK, FALSE);
346 }
347 }
348
349 /**
350 * Manage SELECT button clicks.
351 *
352 * This function is called when the user clicks on one of the SELECT buttons.
353 * the data parameter contains information about which button has been clicked.
354 */
select_location(GtkWidget * widget,gpointer data)355 static void select_location(GtkWidget * widget, gpointer data)
356 {
357 guint mode = GPOINTER_TO_UINT(data);
358 guint flags;
359 gchar *qthloc;
360 gchar *qthwx;
361 gfloat qthlat;
362 gfloat qthlon;
363 guint qthalt;
364 gboolean selected = FALSE;
365
366 (void)widget; /* avoid unused parameter compiler warning */
367
368 switch (mode)
369 {
370 /* We distinguish only between WX mode and "everything else".
371 Although a value != 1 or 2 is definitely a bug, we need to
372 have some sensible fall-back.
373 */
374 case SELECTION_MODE_WX:
375 flags = TREE_COL_FLAG_NAME | TREE_COL_FLAG_WX;
376 break;
377
378 default:
379 flags = TREE_COL_FLAG_NAME |
380 TREE_COL_FLAG_LAT |
381 TREE_COL_FLAG_LON | TREE_COL_FLAG_ALT | TREE_COL_FLAG_WX;
382
383 mode = SELECTION_MODE_LOC;
384 break;
385 }
386
387 selected =
388 loc_tree_create(NULL, flags, &qthloc, &qthlat, &qthlon, &qthalt,
389 &qthwx);
390
391 if (selected)
392 {
393 /* update widgets */
394 switch (mode)
395 {
396
397 case SELECTION_MODE_WX:
398 gtk_entry_set_text(GTK_ENTRY(wx), qthwx);
399 break;
400
401 case SELECTION_MODE_LOC:
402 gtk_entry_set_text(GTK_ENTRY(location), qthloc);
403 gtk_entry_set_text(GTK_ENTRY(wx), qthwx);
404
405 gtk_spin_button_set_value(GTK_SPIN_BUTTON(lat),
406 (gdouble) fabs(qthlat));
407 if (qthlat < 0.00)
408 gtk_combo_box_set_active(GTK_COMBO_BOX(ns), 1);
409 else
410 gtk_combo_box_set_active(GTK_COMBO_BOX(ns), 0);
411
412 gtk_spin_button_set_value(GTK_SPIN_BUTTON(lon),
413 (gdouble) fabs(qthlon));
414 if (qthlon < 0.00)
415 gtk_combo_box_set_active(GTK_COMBO_BOX(ew), 1);
416 else
417 gtk_combo_box_set_active(GTK_COMBO_BOX(ew), 0);
418
419 gtk_spin_button_set_value(GTK_SPIN_BUTTON(alt), qthalt);
420
421 break;
422
423 default:
424 /*** FIXME: add some error reporting */
425 break;
426 }
427
428 /* free some memory */
429 g_free(qthloc);
430 g_free(qthwx);
431 }
432
433 /* else do nothing; we are finished */
434 }
435
436 /**
437 * Manage coordinate changes.
438 *
439 * This function is called when the qth coordinates change. The change can
440 * be either one of the spin buttons or the combo boxes. It reads the
441 * coordinates and the calculates the new Maidenhead locator square.
442 */
latlon_changed(GtkWidget * widget,gpointer data)443 static void latlon_changed(GtkWidget * widget, gpointer data)
444 {
445 gchar *locator;
446 gint retcode;
447 gdouble latf, lonf;
448
449 (void)widget; /* avoid unused parameter compiler warning */
450 (void)data; /* avoid unused parameter compiler warning */
451
452 locator = g_try_malloc(7);
453
454 /* no need to check locator != NULL, since hamlib func will do it for us
455 and return RIGEINVAL
456 */
457 lonf = gtk_spin_button_get_value(GTK_SPIN_BUTTON(lon));
458 latf = gtk_spin_button_get_value(GTK_SPIN_BUTTON(lat));
459
460 /* set the correct sign */
461 if (gtk_combo_box_get_active(GTK_COMBO_BOX(ns)))
462 {
463 /* index 1 => South */
464 latf = -latf;
465 }
466
467 if (gtk_combo_box_get_active(GTK_COMBO_BOX(ew)))
468 {
469 /* index 1 => Wesr */
470 lonf = -lonf;
471 }
472
473 retcode = longlat2locator(lonf, latf, locator, 3);
474
475 if (retcode == RIG_OK)
476 {
477 /* debug message */
478 sat_log_log(SAT_LOG_LEVEL_DEBUG,
479 _("%s:%s: %.2f %.2f => %s"),
480 __FILE__, __func__,
481 gtk_spin_button_get_value(GTK_SPIN_BUTTON(lon)),
482 gtk_spin_button_get_value(GTK_SPIN_BUTTON(lat)), locator);
483
484 g_signal_handler_block(qra, qrasigid);
485
486 gtk_entry_set_text(GTK_ENTRY(qra), locator);
487
488 g_signal_handler_unblock(qra, qrasigid);
489 }
490 else
491 {
492 /* send an error message and don't update */
493 sat_log_log(SAT_LOG_LEVEL_ERROR,
494 _("%s:%d: Error converting lon/lat to locator"),
495 __FILE__, __LINE__);
496 }
497
498
499 if (locator)
500 g_free(locator);
501 }
502
503 /**
504 * Manage locator changes.
505 *
506 * This function is called when the Maidenhead locator is changed.
507 * It will calculate the new coordinates and update the spin butrtons and
508 * the combo boxes.
509 */
qra_changed(GtkEntry * entry,gpointer data)510 static void qra_changed(GtkEntry * entry, gpointer data)
511 {
512 gint retcode;
513 gdouble latf, lonf;
514 gchar *msg;
515
516 (void)entry; /* avoid unused parameter compiler warning */
517 (void)data; /* avoid unused parameter compiler warning */
518
519 retcode =
520 locator2longlat(&lonf, &latf, gtk_entry_get_text(GTK_ENTRY(qra)));
521
522 if (retcode == RIG_OK)
523 {
524
525 /* debug message */
526 sat_log_log(SAT_LOG_LEVEL_DEBUG,
527 _("%s:%s: %s => %.2f %.2f"),
528 __FILE__, __func__,
529 gtk_entry_get_text(GTK_ENTRY(qra)), lonf, latf);
530
531 /* block signal emissions for lat/lon widgets */
532 g_signal_handler_block(lat, latsigid);
533 g_signal_handler_block(lon, lonsigid);
534 g_signal_handler_block(ns, nssigid);
535 g_signal_handler_block(ew, ewsigid);
536 g_signal_handler_block(qra, qrasigid);
537
538 /* update widgets */
539 if (latf < 0.00)
540 gtk_combo_box_set_active(GTK_COMBO_BOX(ns), 1);
541 else
542 gtk_combo_box_set_active(GTK_COMBO_BOX(ns), 0);
543
544 if (lonf < 0.00)
545 gtk_combo_box_set_active(GTK_COMBO_BOX(ew), 1);
546 else
547 gtk_combo_box_set_active(GTK_COMBO_BOX(ew), 0);
548
549 gtk_spin_button_set_value(GTK_SPIN_BUTTON(lat), fabs(latf));
550 gtk_spin_button_set_value(GTK_SPIN_BUTTON(lon), fabs(lonf));
551
552 /* make sure text is upper case */
553 msg = g_ascii_strup(gtk_entry_get_text(GTK_ENTRY(qra)), -1);
554 gtk_entry_set_text(GTK_ENTRY(qra), msg);
555 g_free(msg);
556
557 /* unblock signal emissions */
558 g_signal_handler_unblock(lat, latsigid);
559 g_signal_handler_unblock(lon, lonsigid);
560 g_signal_handler_unblock(ns, nssigid);
561 g_signal_handler_unblock(ew, ewsigid);
562 g_signal_handler_unblock(qra, qrasigid);
563
564 }
565 else
566 {
567 /* send an error message and don't update */
568 sat_log_log(SAT_LOG_LEVEL_ERROR,
569 _("%s:%d: Invalid locator: %s"),
570 __FILE__, __LINE__, gtk_entry_get_text(GTK_ENTRY(qra)));
571 }
572
573 }
574
create_editor_widgets(GtkTreeView * treeview,gboolean new)575 static GtkWidget *create_editor_widgets(GtkTreeView * treeview, gboolean new)
576 {
577 GtkWidget *table;
578 GtkWidget *label;
579 GtkWidget *locbut;
580 GtkWidget *wxbut;
581
582 table = gtk_grid_new();
583 gtk_grid_set_column_homogeneous(GTK_GRID(table), FALSE);
584 gtk_grid_set_row_homogeneous(GTK_GRID(table), FALSE);
585 gtk_grid_set_column_spacing(GTK_GRID(table), 5);
586 gtk_grid_set_row_spacing(GTK_GRID(table), 5);
587 gtk_container_set_border_width(GTK_CONTAINER(table), 5);
588
589 /* QTH name */
590 label = gtk_label_new(_("Name"));
591 g_object_set(label, "xalign", 0.0f, "yalign", 0.5f, NULL);
592 gtk_grid_attach(GTK_GRID(table), label, 0, 0, 1, 1);
593
594 name = gtk_entry_new();
595 gtk_entry_set_max_length(GTK_ENTRY(name), 25);
596 gtk_widget_set_tooltip_text(name,
597 _
598 ("Enter a short name for this ground station, "
599 "e.g. callsign.\n"
600 "Allowed characters: 0..9, a..z, A..Z, - and _"));
601 gtk_grid_attach(GTK_GRID(table), name, 1, 0, 3, 1);
602
603 /* attach changed signal so that we can enable OK button when
604 a proper name has been entered
605 */
606 g_signal_connect(name, "changed", G_CALLBACK(name_changed), NULL);
607
608 /* QTH description */
609 label = gtk_label_new(_("Description"));
610 g_object_set(label, "xalign", 0.0f, "yalign", 0.5f, NULL);
611 gtk_grid_attach(GTK_GRID(table), label, 0, 1, 1, 1);
612
613 desc = gtk_entry_new();
614 gtk_entry_set_max_length(GTK_ENTRY(desc), 256);
615 gtk_widget_set_tooltip_text(desc,
616 _("Enter an optional description for this"
617 " ground station."));
618 gtk_grid_attach(GTK_GRID(table), desc, 1, 1, 3, 1);
619
620 /* location */
621 label = gtk_label_new(_("Location"));
622 g_object_set(label, "xalign", 0.0f, "yalign", 0.5f, NULL);
623 gtk_grid_attach(GTK_GRID(table), label, 0, 2, 1, 1);
624
625 location = gtk_entry_new();
626 gtk_entry_set_max_length(GTK_ENTRY(location), 50);
627 gtk_widget_set_tooltip_text(location,
628 _("Optional location of the ground station, "
629 "e.g. Copenhagen, Denmark."));
630 gtk_grid_attach(GTK_GRID(table), location, 1, 2, 2, 1);
631
632 locbut = gtk_button_new_with_label(_("Select"));
633 gtk_widget_set_tooltip_text(locbut, _("Select a location from a list"));
634 g_signal_connect(locbut, "clicked", G_CALLBACK(select_location),
635 GUINT_TO_POINTER(SELECTION_MODE_LOC));
636 gtk_grid_attach(GTK_GRID(table), locbut, 3, 2, 1, 1);
637
638
639 /* latitude */
640 label = gtk_label_new(_("Latitude (\302\260)"));
641 g_object_set(label, "xalign", 0.0f, "yalign", 0.5f, NULL);
642 gtk_grid_attach(GTK_GRID(table), label, 0, 3, 1, 1);
643
644 lat = gtk_spin_button_new_with_range(0.00, 90.00, 0.0001);
645 gtk_spin_button_set_increments(GTK_SPIN_BUTTON(lat), 0.0001, 1.0);
646 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(lat), TRUE);
647 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(lat), 4);
648 gtk_widget_set_tooltip_text(lat,
649 _("Select the latitude of the ground station "
650 "in decimal degrees."));
651 gtk_grid_attach(GTK_GRID(table), lat, 1, 3, 1, 1);
652
653 ns = gtk_combo_box_text_new();
654 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(ns), _("North"));
655 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(ns), _("South"));
656 gtk_combo_box_set_active(GTK_COMBO_BOX(ns), 0);
657 gtk_grid_attach(GTK_GRID(table), ns, 2, 3, 1, 1);
658
659 /* longitude */
660 label = gtk_label_new(_("Longitude (\302\260)"));
661 g_object_set(label, "xalign", 0.0f, "yalign", 0.5f, NULL);
662 gtk_grid_attach(GTK_GRID(table), label, 0, 4, 1, 1);
663
664 lon = gtk_spin_button_new_with_range(0.00, 180.00, 0.0001);
665 gtk_spin_button_set_increments(GTK_SPIN_BUTTON(lon), 0.0001, 1.0);
666 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(lon), TRUE);
667 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(lon), 4);
668 gtk_widget_set_tooltip_text(lon,
669 _("Select the longitude of the ground station "
670 "in decimal degrees."));
671 gtk_grid_attach(GTK_GRID(table), lon, 1, 4, 1, 1);
672
673 ew = gtk_combo_box_text_new();
674 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(ew), _("East"));
675 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(ew), _("West"));
676 gtk_combo_box_set_active(GTK_COMBO_BOX(ew), 0);
677 gtk_grid_attach(GTK_GRID(table), ew, 2, 4, 1, 1);
678
679 /* connect lat/lon spinners and combos to callback
680 remember signal id so that we can block signals
681 while doing automatic cross-updates
682 */
683 latsigid = g_signal_connect(lat, "value-changed",
684 G_CALLBACK(latlon_changed), NULL);
685 lonsigid = g_signal_connect(lon, "value-changed",
686 G_CALLBACK(latlon_changed), NULL);
687 nssigid = g_signal_connect(ns, "changed",
688 G_CALLBACK(latlon_changed), NULL);
689 ewsigid = g_signal_connect(ew, "changed",
690 G_CALLBACK(latlon_changed), NULL);
691
692 /* QRA locator */
693 label = gtk_label_new(_("Locator"));
694 g_object_set(label, "xalign", 0.0f, "yalign", 0.5f, NULL);
695 gtk_grid_attach(GTK_GRID(table), label, 0, 5, 1, 1);
696
697 qra = gtk_entry_new();
698 gtk_entry_set_max_length(GTK_ENTRY(qra), 6);
699 gtk_widget_set_tooltip_text(qra, _("Maidenhead locator grid."));
700 qrasigid = g_signal_connect(qra, "changed", G_CALLBACK(qra_changed), NULL);
701 gtk_grid_attach(GTK_GRID(table), qra, 1, 5, 1, 1);
702
703 /* altitude */
704 label = gtk_label_new(_("Altitude"));
705 g_object_set(label, "xalign", 0.0f, "yalign", 0.5f, NULL);
706 gtk_grid_attach(GTK_GRID(table), label, 0, 6, 1, 1);
707
708 alt = gtk_spin_button_new_with_range(0, 5000, 1);
709 gtk_spin_button_set_increments(GTK_SPIN_BUTTON(alt), 1, 100);
710 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(alt), TRUE);
711 gtk_widget_set_tooltip_text(alt,
712 _("Select the altitude of the ground station "
713 "in meters or feet "
714 "depending on your settings"));
715 gtk_grid_attach(GTK_GRID(table), alt, 1, 6, 1, 1);
716
717 if (sat_cfg_get_bool(SAT_CFG_BOOL_USE_IMPERIAL))
718 label = gtk_label_new(_("ft ASL"));
719 else
720 label = gtk_label_new(_("m ASL"));
721
722 g_object_set(label, "xalign", 0.0f, "yalign", 0.5f, NULL);
723 gtk_grid_attach(GTK_GRID(table), label, 2, 6, 1, 1);
724
725 /* weather station */
726 label = gtk_label_new(_("Weather St"));
727 g_object_set(label, "xalign", 0.0f, "yalign", 0.5f, NULL);
728 gtk_grid_attach(GTK_GRID(table), label, 0, 7, 1, 1);
729
730 wx = gtk_entry_new();
731 gtk_entry_set_max_length(GTK_ENTRY(wx), 4);
732 gtk_widget_set_tooltip_text(wx, _("Four letter code for weather station"));
733 gtk_grid_attach(GTK_GRID(table), wx, 1, 7, 2, 1);
734
735 wxbut = gtk_button_new_with_label(_("Select"));
736 gtk_widget_set_tooltip_text(wxbut, _("Select a weather station"));
737 g_signal_connect(wxbut, "clicked", G_CALLBACK(select_location),
738 GUINT_TO_POINTER(SELECTION_MODE_WX));
739 gtk_grid_attach(GTK_GRID(table), wxbut, 3, 7, 1, 1);
740
741 #ifdef HAS_LIBGPS
742 /* GPSD enabled */
743 label = gtk_label_new(_("QTH Type"));
744 g_object_set(label, "xalign", 0.0f, "yalign", 0.5f, NULL);
745 gtk_grid_attach(GTK_GRID(table), label, 0, 8, 1, 1);
746
747 type = gtk_combo_box_text_new();
748 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(type), _("Static"));
749 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(type), _("GPSD"));
750 gtk_combo_box_set_active(GTK_COMBO_BOX(type), 0);
751 gtk_widget_set_tooltip_text(type,
752 _("A qth can be static, ie. it does not "
753 "change, or gpsd based for computers with "
754 "gps attached."));
755 gtk_grid_attach(GTK_GRID(table), type, 1, 8, 1, 1);
756
757 /* GPSD Server */
758 label = gtk_label_new(_("GPSD Server"));
759 g_object_set(label, "xalign", 0.0f, "yalign", 0.5f, NULL);
760 gtk_grid_attach(GTK_GRID(table), label, 0, 9, 1, 1);
761
762 server = gtk_entry_new();
763 gtk_entry_set_max_length(GTK_ENTRY(server), 6000);
764 gtk_widget_set_tooltip_text(server, _("GPSD Server."));
765 gtk_grid_attach(GTK_GRID(table), server, 1, 9, 1, 1);
766
767 /* GPSD Port */
768 label = gtk_label_new(_("GPSD Port"));
769 g_object_set(label, "xalign", 0.0f, "yalign", 0.5f, NULL);
770 gtk_grid_attach(GTK_GRID(table), label, 0, 10, 1, 1);
771
772 port = gtk_spin_button_new_with_range(0, 32768, 1);
773 gtk_spin_button_set_increments(GTK_SPIN_BUTTON(port), 1, 100);
774 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(port), TRUE);
775 gtk_widget_set_tooltip_text(port,
776 _("Set the port for GPSD to use. Default for "
777 "gpsd is 2947."));
778 gtk_grid_attach(GTK_GRID(table), port, 1, 10, 1, 1);
779 #endif
780
781 if (!new)
782 update_widgets(treeview);
783
784 gtk_widget_show_all(table);
785
786 return table;
787 }
788
789 /*
790 * Add or edit a QTH entry.
791 *
792 * The parameter new is used to indicate whether a new entry should be
793 * created or just edit the one selected in the treeview.
794 */
sat_pref_qth_editor_run(GtkTreeView * treeview,gboolean new)795 void sat_pref_qth_editor_run(GtkTreeView * treeview, gboolean new)
796 {
797 gint response;
798 gboolean finished = FALSE;
799
800 /* crate dialog and add contents */
801 dialog = gtk_dialog_new_with_buttons(_("Edit ground station data"),
802 GTK_WINDOW(window),
803 GTK_DIALOG_MODAL |
804 GTK_DIALOG_DESTROY_WITH_PARENT,
805 "_Clear", GTK_RESPONSE_REJECT,
806 "_Cancel", GTK_RESPONSE_CANCEL,
807 "_OK", GTK_RESPONSE_OK, NULL);
808
809 /* disable OK button to begin with */
810 gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog),
811 GTK_RESPONSE_OK, FALSE);
812
813 gtk_container_add(GTK_CONTAINER
814 (gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
815 create_editor_widgets(treeview, new));
816
817 /* this hacky-thing is to keep the dialog running in case the
818 CLEAR button is plressed. OK and CANCEL will exit the loop
819 */
820 while (!finished)
821 {
822 response = gtk_dialog_run(GTK_DIALOG(dialog));
823
824 switch (response)
825 {
826 case GTK_RESPONSE_OK:
827 /* OK */
828 if (apply_changes(treeview, new))
829 finished = TRUE;
830 else
831 finished = FALSE;
832
833 break;
834
835 case GTK_RESPONSE_REJECT:
836 /* CLEAR */
837 clear_widgets();
838 break;
839
840 default:
841 /* Everything else is considered CANCEL */
842 finished = TRUE;
843 break;
844 }
845 }
846
847 gtk_widget_destroy(dialog);
848 }
849