1 /*
2 Gpredict: Real-time satellite tracking and orbit prediction program
3
4 Copyright (C) 2001-2017 Alexandru Csete, OZ9AEC.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, visit http://www.fsf.org/
18 */
19 #ifdef HAVE_CONFIG_H
20 #include <build-config.h>
21 #endif
22 #include <glib/gi18n.h>
23 #include <glib/gstdio.h>
24 #include <gtk/gtk.h>
25
26 #include "compat.h"
27 #include "gpredict-utils.h"
28 #include "radio-conf.h"
29 #include "sat-cfg.h"
30 #include "sat-log.h"
31 #include "sat-pref-rig.h"
32 #include "sat-pref-rig-data.h"
33 #include "sat-pref-rig-editor.h"
34
35
36 extern GtkWidget *window; /* dialog window defined in sat-pref.c */
37 static GtkWidget *addbutton;
38 static GtkWidget *editbutton;
39 static GtkWidget *delbutton;
40 static GtkWidget *riglist;
41
create_and_fill_model()42 static GtkTreeModel *create_and_fill_model()
43 {
44 GtkListStore *liststore; /* the list store data structure */
45 GtkTreeIter item; /* new item added to the list store */
46 GDir *dir = NULL; /* directory handle */
47 GError *error = NULL; /* error flag and info */
48 gchar *dirname; /* directory name */
49 gchar **vbuff;
50 const gchar *filename; /* file name */
51 radio_conf_t conf;
52
53 /* create a new list store */
54 liststore = gtk_list_store_new(RIG_LIST_COL_NUM, G_TYPE_STRING, // name
55 G_TYPE_STRING, // host
56 G_TYPE_INT, // port
57 G_TYPE_INT, // type
58 G_TYPE_INT, // PTT
59 G_TYPE_INT, // VFO Up
60 G_TYPE_INT, // VFO Down
61 G_TYPE_DOUBLE, // LO DOWN
62 G_TYPE_DOUBLE, // LO UO
63 G_TYPE_BOOLEAN, // AOS signalling
64 G_TYPE_BOOLEAN // LOS signalling
65 );
66
67 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(liststore),
68 RIG_LIST_COL_NAME,
69 GTK_SORT_ASCENDING);
70 /* open configuration directory */
71 dirname = get_hwconf_dir();
72
73 dir = g_dir_open(dirname, 0, &error);
74 if (dir)
75 {
76 /* read each .rig file */
77 while ((filename = g_dir_read_name(dir)))
78 {
79 if (g_str_has_suffix(filename, ".rig"))
80 {
81 vbuff = g_strsplit(filename, ".rig", 0);
82 conf.name = g_strdup(vbuff[0]);
83 g_strfreev(vbuff);
84
85 if (radio_conf_read(&conf))
86 {
87 /* insert conf into liststore */
88 gtk_list_store_append(liststore, &item);
89 gtk_list_store_set(liststore, &item,
90 RIG_LIST_COL_NAME, conf.name,
91 RIG_LIST_COL_HOST, conf.host,
92 RIG_LIST_COL_PORT, conf.port,
93 RIG_LIST_COL_TYPE, conf.type,
94 RIG_LIST_COL_PTT, conf.ptt,
95 RIG_LIST_COL_VFOUP, conf.vfoUp,
96 RIG_LIST_COL_VFODOWN, conf.vfoDown,
97 RIG_LIST_COL_LO, conf.lo,
98 RIG_LIST_COL_LOUP, conf.loup,
99 RIG_LIST_COL_SIGAOS, conf.signal_aos,
100 RIG_LIST_COL_SIGLOS, conf.signal_los,
101 -1);
102
103 sat_log_log(SAT_LOG_LEVEL_DEBUG,
104 _("%s:%d: Read %s"),
105 __FILE__, __LINE__, filename);
106 /* clean up memory */
107 if (conf.name)
108 g_free(conf.name);
109
110 if (conf.host)
111 g_free(conf.host);
112 }
113 else
114 {
115 /* there was an error */
116 sat_log_log(SAT_LOG_LEVEL_ERROR,
117 _("%s:%d: Failed to read %s"),
118 __FILE__, __LINE__, conf.name);
119
120 g_free(conf.name);
121 }
122 }
123 }
124 }
125 else
126 {
127 sat_log_log(SAT_LOG_LEVEL_ERROR,
128 _("%s:%d: Failed to open hwconf dir (%s)"),
129 __FILE__, __LINE__, error->message);
130 g_clear_error(&error);
131 }
132
133 g_free(dirname);
134 g_dir_close(dir);
135
136 return GTK_TREE_MODEL(liststore);
137 }
138
139 /**
140 * Render configuration name.
141 *
142 * @param col Pointer to the tree view column.
143 * @param renderer Pointer to the renderer.
144 * @param model Pointer to the tree model.
145 * @param iter Pointer to the tree iterator.
146 * @param column The column number in the model.
147 *
148 * This function renders the configuration name onto the riglist. Although
149 * the configuration name is a plain string, it contains the file name of the
150 * configuration file and we want to strip the .rig extension.
151 */
render_name(GtkTreeViewColumn * col,GtkCellRenderer * renderer,GtkTreeModel * model,GtkTreeIter * iter,gpointer column)152 static void render_name(GtkTreeViewColumn * col,
153 GtkCellRenderer * renderer,
154 GtkTreeModel * model,
155 GtkTreeIter * iter, gpointer column)
156 {
157 gchar *fname;
158 gchar **buff;
159 guint coli = GPOINTER_TO_UINT(column);
160
161 (void)col;
162
163 gtk_tree_model_get(model, iter, coli, &fname, -1);
164
165 buff = g_strsplit(fname, ".rig", 0);
166 g_object_set(renderer, "text", buff[0], NULL);
167
168 g_strfreev(buff);
169 g_free(fname);
170 }
171
172 /**
173 * Render radio type.
174 *
175 * @param col Pointer to the tree view column.
176 * @param renderer Pointer to the renderer.
177 * @param model Pointer to the tree model.
178 * @param iter Pointer to the tree iterator.
179 * @param column The column number in the model.
180 *
181 * This function renders the radio type onto the riglist.
182 */
render_type(GtkTreeViewColumn * col,GtkCellRenderer * renderer,GtkTreeModel * model,GtkTreeIter * iter,gpointer column)183 static void render_type(GtkTreeViewColumn * col,
184 GtkCellRenderer * renderer,
185 GtkTreeModel * model,
186 GtkTreeIter * iter, gpointer column)
187 {
188 guint type;
189 guint coli = GPOINTER_TO_UINT(column);
190
191 (void)col;
192
193 gtk_tree_model_get(model, iter, coli, &type, -1);
194
195 switch (type)
196 {
197 case RIG_TYPE_RX:
198 g_object_set(renderer, "text", _("RX only"), NULL);
199 break;
200
201 case RIG_TYPE_TX:
202 g_object_set(renderer, "text", _("TX only"), NULL);
203 break;
204
205 case RIG_TYPE_TRX:
206 g_object_set(renderer, "text", _("RX + TX"), NULL);
207 break;
208
209 case RIG_TYPE_DUPLEX:
210 g_object_set(renderer, "text", _("Duplex"), NULL);
211 break;
212
213 case RIG_TYPE_TOGGLE_AUTO:
214 g_object_set(renderer, "text", _("FT817/857/897 (auto)"), NULL);
215 break;
216
217 case RIG_TYPE_TOGGLE_MAN:
218 g_object_set(renderer, "text", _("FT817/857/897 (man)"), NULL);
219 break;
220
221 default:
222 g_object_set(renderer, "text", _("ERROR"), NULL);
223 break;
224 }
225
226 }
227
228 /**
229 * Render PTT status usage.
230 *
231 * @param col Pointer to the tree view column.
232 * @param renderer Pointer to the renderer.
233 * @param model Pointer to the tree model.
234 * @param iter Pointer to the tree iterator.
235 * @param column The column number in the model.
236 *
237 * This function renders the PTT status usage onto the riglist.
238 */
render_ptt(GtkTreeViewColumn * col,GtkCellRenderer * renderer,GtkTreeModel * model,GtkTreeIter * iter,gpointer column)239 static void render_ptt(GtkTreeViewColumn * col,
240 GtkCellRenderer * renderer,
241 GtkTreeModel * model,
242 GtkTreeIter * iter, gpointer column)
243 {
244 gint ptt;
245 guint coli = GPOINTER_TO_UINT(column);
246
247 (void)col;
248
249 gtk_tree_model_get(model, iter, coli, &ptt, -1);
250
251 switch (ptt)
252 {
253 case PTT_TYPE_NONE:
254 g_object_set(renderer, "text", _("None"), NULL);
255 break;
256 case PTT_TYPE_CAT:
257 g_object_set(renderer, "text", _("PTT"), NULL);
258 break;
259 case PTT_TYPE_DCD:
260 g_object_set(renderer, "text", _("DCD"), NULL);
261 break;
262 default:
263 g_object_set(renderer, "text", _("None"), NULL);
264 break;
265 }
266 }
267
268 /**
269 * Render Local Oscillator frequency
270 *
271 * @param col Pointer to the tree view column.
272 * @param renderer Pointer to the renderer.
273 * @param model Pointer to the tree model.
274 * @param iter Pointer to the tree iterator.
275 * @param column The column number in the model.
276 *
277 * This function is used to render the local oscillator frequency. We
278 * need a special renderer so that we can automatically render as MHz
279 * instead of Hz.
280 */
render_lo(GtkTreeViewColumn * col,GtkCellRenderer * renderer,GtkTreeModel * model,GtkTreeIter * iter,gpointer column)281 static void render_lo(GtkTreeViewColumn * col,
282 GtkCellRenderer * renderer,
283 GtkTreeModel * model,
284 GtkTreeIter * iter, gpointer column)
285 {
286 gdouble number;
287 gchar *buff;
288 guint coli = GPOINTER_TO_UINT(column);
289
290 (void)col;
291
292 gtk_tree_model_get(model, iter, coli, &number, -1);
293
294 /* convert to MHz */
295 number /= 1000000.0;
296 buff = g_strdup_printf("%.0f MHz", number);
297 g_object_set(renderer, "text", buff, NULL);
298 g_free(buff);
299 }
300
301 /**
302 * Render VFO selection.
303 *
304 * @param col Pointer to the tree view column.
305 * @param renderer Pointer to the renderer.
306 * @param model Pointer to the tree model.
307 * @param iter Pointer to the tree iterator.
308 * @param column The column number in the model.
309 *
310 * This function is used to render the VFO up/down selections for
311 * full duplex radios.
312 */
render_vfo(GtkTreeViewColumn * col,GtkCellRenderer * renderer,GtkTreeModel * model,GtkTreeIter * iter,gpointer column)313 static void render_vfo(GtkTreeViewColumn * col,
314 GtkCellRenderer * renderer,
315 GtkTreeModel * model,
316 GtkTreeIter * iter, gpointer column)
317 {
318 gint number;
319 gchar *buff;
320 guint coli = GPOINTER_TO_UINT(column);
321
322 (void)col;
323
324 gtk_tree_model_get(model, iter, coli, &number, -1);
325
326 switch (number)
327 {
328
329 case VFO_A:
330 buff = g_strdup_printf("VFO A");
331 break;
332
333 case VFO_B:
334 buff = g_strdup_printf("VFO B");
335 break;
336
337 case VFO_MAIN:
338 buff = g_strdup_printf("Main");
339 break;
340
341 case VFO_SUB:
342 buff = g_strdup_printf("Sub");
343 break;
344
345 default:
346 buff = g_strdup_printf("-");
347 break;
348 }
349
350 g_object_set(renderer, "text", buff, NULL);
351 g_free(buff);
352 }
353
render_signal(GtkTreeViewColumn * col,GtkCellRenderer * renderer,GtkTreeModel * model,GtkTreeIter * iter,gpointer column)354 static void render_signal(GtkTreeViewColumn * col, GtkCellRenderer * renderer,
355 GtkTreeModel * model, GtkTreeIter * iter,
356 gpointer column)
357 {
358 gboolean signal_enabled;
359 guint coli = GPOINTER_TO_UINT(column);
360
361 (void)col;
362
363 gtk_tree_model_get(model, iter, coli, &signal_enabled, -1);
364 g_object_set(renderer, "text", signal_enabled ? "YES" : "NO", NULL);
365 }
366
367 /**
368 * Add a new radio configuration
369 *
370 * @param button Pointer to the Add button.
371 * @param data User data (null).
372 *
373 * This function executes the radio configuration editor with the "new"
374 * flag set to TRUE.
375 */
edit_cb(GtkWidget * button,gpointer data)376 static void edit_cb(GtkWidget * button, gpointer data)
377 {
378 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(riglist));
379 GtkTreeModel *selmod;
380 GtkTreeSelection *selection;
381 GtkTreeIter iter;
382
383 (void)button;
384 (void)data;
385
386 radio_conf_t conf = {
387 .name = NULL,
388 .host = NULL,
389 .port = 4532,
390 .type = RIG_TYPE_RX,
391 .ptt = 0,
392 .vfoUp = 0,
393 .vfoDown = 0,
394 .lo = 0.0,
395 .loup = 0.0,
396 .signal_aos = FALSE,
397 .signal_los = FALSE
398 };
399
400 /* If there are no entries, we have a bug since the button should
401 have been disabled. */
402 if (gtk_tree_model_iter_n_children(model, NULL) < 1)
403 {
404 sat_log_log(SAT_LOG_LEVEL_ERROR,
405 _("%s:%s: Edit button should have been disabled."),
406 __FILE__, __func__);
407 //gtk_widget_set_sensitive (button, FALSE);
408
409 return;
410 }
411
412 /* get selected row
413 FIXME: do we really need to work with two models?
414 */
415 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(riglist));
416 if (gtk_tree_selection_get_selected(selection, &selmod, &iter))
417 {
418 gtk_tree_model_get(model, &iter,
419 RIG_LIST_COL_NAME, &conf.name,
420 RIG_LIST_COL_HOST, &conf.host,
421 RIG_LIST_COL_PORT, &conf.port,
422 RIG_LIST_COL_TYPE, &conf.type,
423 RIG_LIST_COL_PTT, &conf.ptt,
424 RIG_LIST_COL_VFOUP, &conf.vfoUp,
425 RIG_LIST_COL_VFODOWN, &conf.vfoDown,
426 RIG_LIST_COL_LO, &conf.lo,
427 RIG_LIST_COL_LOUP, &conf.loup,
428 RIG_LIST_COL_SIGAOS, &conf.signal_aos,
429 RIG_LIST_COL_SIGLOS, &conf.signal_los, -1);
430 }
431 else
432 {
433 GtkWidget *dialog;
434
435 dialog = gtk_message_dialog_new(GTK_WINDOW(window),
436 GTK_DIALOG_MODAL |
437 GTK_DIALOG_DESTROY_WITH_PARENT,
438 GTK_MESSAGE_ERROR,
439 GTK_BUTTONS_OK,
440 _("Select the radio you want to edit\n"
441 "and try again!"));
442 gtk_dialog_run(GTK_DIALOG(dialog));
443 gtk_widget_destroy(dialog);
444
445 return;
446 }
447
448 /* run radio configuration editor */
449 sat_pref_rig_editor_run(&conf);
450
451 /* apply changes */
452 if (conf.name != NULL)
453 {
454 gtk_list_store_set(GTK_LIST_STORE(model), &iter,
455 RIG_LIST_COL_NAME, conf.name,
456 RIG_LIST_COL_HOST, conf.host,
457 RIG_LIST_COL_PORT, conf.port,
458 RIG_LIST_COL_TYPE, conf.type,
459 RIG_LIST_COL_PTT, conf.ptt,
460 RIG_LIST_COL_VFOUP, conf.vfoUp,
461 RIG_LIST_COL_VFODOWN, conf.vfoDown,
462 RIG_LIST_COL_LO, conf.lo,
463 RIG_LIST_COL_LOUP, conf.loup,
464 RIG_LIST_COL_SIGAOS, conf.signal_aos,
465 RIG_LIST_COL_SIGLOS, conf.signal_los, -1);
466 }
467
468 /* clean up memory */
469 if (conf.name)
470 g_free(conf.name);
471
472 if (conf.host != NULL)
473 g_free(conf.host);
474 }
475
row_activated_cb(GtkTreeView * tree_view,GtkTreePath * path,GtkTreeViewColumn * column,gpointer user_data)476 static void row_activated_cb(GtkTreeView * tree_view,
477 GtkTreePath * path,
478 GtkTreeViewColumn * column, gpointer user_data)
479 {
480 (void)tree_view;
481 (void)path;
482 (void)column;
483 (void)user_data;
484
485 edit_cb(editbutton, NULL);
486 }
487
488 /* Radio configuration list widget. */
create_rig_list()489 static void create_rig_list()
490 {
491 GtkTreeModel *model;
492 GtkCellRenderer *renderer;
493 GtkTreeViewColumn *column;
494
495 riglist = gtk_tree_view_new();
496
497 model = create_and_fill_model();
498 gtk_tree_view_set_model(GTK_TREE_VIEW(riglist), model);
499 g_object_unref(model);
500
501 /* Conf name */
502 renderer = gtk_cell_renderer_text_new();
503 column =
504 gtk_tree_view_column_new_with_attributes(_("Config Name"), renderer,
505 "text", RIG_LIST_COL_NAME,
506 NULL);
507 gtk_tree_view_column_set_cell_data_func(column, renderer, render_name,
508 GUINT_TO_POINTER
509 (RIG_LIST_COL_NAME), NULL);
510 gtk_tree_view_insert_column(GTK_TREE_VIEW(riglist), column, -1);
511
512 /* Host */
513 renderer = gtk_cell_renderer_text_new();
514 column = gtk_tree_view_column_new_with_attributes(_("Host"), renderer,
515 "text",
516 RIG_LIST_COL_HOST, NULL);
517 gtk_tree_view_insert_column(GTK_TREE_VIEW(riglist), column, -1);
518
519 /* port */
520 renderer = gtk_cell_renderer_text_new();
521 column = gtk_tree_view_column_new_with_attributes(_("Port"), renderer,
522 "text",
523 RIG_LIST_COL_PORT, NULL);
524 gtk_tree_view_insert_column(GTK_TREE_VIEW(riglist), column, -1);
525
526 /* rig type */
527 renderer = gtk_cell_renderer_text_new();
528 column = gtk_tree_view_column_new_with_attributes(_("Rig Type"), renderer,
529 "text",
530 RIG_LIST_COL_TYPE, NULL);
531 gtk_tree_view_column_set_cell_data_func(column, renderer, render_type,
532 GUINT_TO_POINTER
533 (RIG_LIST_COL_TYPE), NULL);
534 gtk_tree_view_insert_column(GTK_TREE_VIEW(riglist), column, -1);
535
536 /* PTT */
537 renderer = gtk_cell_renderer_text_new();
538 column =
539 gtk_tree_view_column_new_with_attributes(_("PTT Status"), renderer,
540 "text", RIG_LIST_COL_PTT,
541 NULL);
542 gtk_tree_view_column_set_cell_data_func(column, renderer, render_ptt,
543 GUINT_TO_POINTER(RIG_LIST_COL_PTT),
544 NULL);
545 gtk_tree_view_insert_column(GTK_TREE_VIEW(riglist), column, -1);
546
547 /* VFO Up */
548 renderer = gtk_cell_renderer_text_new();
549 column = gtk_tree_view_column_new_with_attributes(_("VFO Up"), renderer,
550 "text",
551 RIG_LIST_COL_VFOUP,
552 NULL);
553 gtk_tree_view_column_set_cell_data_func(column, renderer, render_vfo,
554 GUINT_TO_POINTER
555 (RIG_LIST_COL_VFOUP), NULL);
556 gtk_tree_view_insert_column(GTK_TREE_VIEW(riglist), column, -1);
557
558 /* VFO Down */
559 renderer = gtk_cell_renderer_text_new();
560 column = gtk_tree_view_column_new_with_attributes(_("VFO Down"), renderer,
561 "text",
562 RIG_LIST_COL_VFODOWN,
563 NULL);
564 gtk_tree_view_column_set_cell_data_func(column, renderer, render_vfo,
565 GUINT_TO_POINTER
566 (RIG_LIST_COL_VFODOWN), NULL);
567 gtk_tree_view_insert_column(GTK_TREE_VIEW(riglist), column, -1);
568
569 /* transverter down */
570 renderer = gtk_cell_renderer_text_new();
571 column = gtk_tree_view_column_new_with_attributes(_("LO Down"), renderer,
572 "text", RIG_LIST_COL_LO,
573 NULL);
574 gtk_tree_view_column_set_cell_data_func(column, renderer,
575 render_lo,
576 GUINT_TO_POINTER(RIG_LIST_COL_LO),
577 NULL);
578 gtk_tree_view_insert_column(GTK_TREE_VIEW(riglist), column, -1);
579
580 /* transverter up */
581 renderer = gtk_cell_renderer_text_new();
582 column = gtk_tree_view_column_new_with_attributes(_("LO Up"), renderer,
583 "text",
584 RIG_LIST_COL_LOUP, NULL);
585 gtk_tree_view_column_set_cell_data_func(column, renderer, render_lo,
586 GUINT_TO_POINTER
587 (RIG_LIST_COL_LOUP), NULL);
588 gtk_tree_view_insert_column(GTK_TREE_VIEW(riglist), column, -1);
589
590 /* AOS signalling */
591 renderer = gtk_cell_renderer_text_new();
592 column =
593 gtk_tree_view_column_new_with_attributes(_("Signal AOS"), renderer,
594 "text", RIG_LIST_COL_SIGAOS,
595 NULL);
596 gtk_tree_view_column_set_cell_data_func(column, renderer, render_signal,
597 GUINT_TO_POINTER
598 (RIG_LIST_COL_SIGAOS), NULL);
599 gtk_tree_view_insert_column(GTK_TREE_VIEW(riglist), column, -1);
600
601 /* LOS signalling */
602 renderer = gtk_cell_renderer_text_new();
603 column =
604 gtk_tree_view_column_new_with_attributes(_("Signal LOS"), renderer,
605 "text", RIG_LIST_COL_SIGLOS,
606 NULL);
607 gtk_tree_view_column_set_cell_data_func(column, renderer, render_signal,
608 GUINT_TO_POINTER
609 (RIG_LIST_COL_SIGLOS), NULL);
610 gtk_tree_view_insert_column(GTK_TREE_VIEW(riglist), column, -1);
611
612 g_signal_connect(riglist, "row-activated", G_CALLBACK(row_activated_cb),
613 riglist);
614 }
615
616 /**
617 * Delete selected radio configuration
618 *
619 * This function is called when the user clicks the Delete button.
620 */
delete_cb(GtkWidget * button,gpointer data)621 static void delete_cb(GtkWidget * button, gpointer data)
622 {
623 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(riglist));
624 GtkTreeSelection *selection;
625 GtkTreeIter iter;
626
627 (void)button;
628 (void)data;
629
630 /* If there are no entries, we have a bug since the button should
631 have been disabled. */
632 if (gtk_tree_model_iter_n_children(model, NULL) < 1)
633 {
634 sat_log_log(SAT_LOG_LEVEL_ERROR,
635 _("%s:%s: Delete button should have been disabled."),
636 __FILE__, __func__);
637 //gtk_widget_set_sensitive (button, FALSE);
638
639 return;
640 }
641
642 /* get selected row */
643 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(riglist));
644 if (gtk_tree_selection_get_selected(selection, NULL, &iter))
645 {
646 gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
647 }
648 else
649 {
650 GtkWidget *dialog;
651
652 dialog = gtk_message_dialog_new(GTK_WINDOW(window),
653 GTK_DIALOG_MODAL |
654 GTK_DIALOG_DESTROY_WITH_PARENT,
655 GTK_MESSAGE_ERROR,
656 GTK_BUTTONS_OK,
657 _("Select the radio you want to "
658 "delete\nand try again!"));
659 gtk_dialog_run(GTK_DIALOG(dialog));
660 gtk_widget_destroy(dialog);
661 }
662 }
663
664 /**
665 * Add a new radio configuration
666 *
667 * @param button Pointer to the Add button.
668 * @param data User data (null).
669 *
670 * This function executes the radio configuration editor with the "new"
671 * flag set to TRUE.
672 */
add_cb(GtkWidget * button,gpointer data)673 static void add_cb(GtkWidget * button, gpointer data)
674 {
675 GtkTreeIter item; /* new item added to the list store */
676 GtkListStore *liststore;
677
678 (void)button;
679 (void)data;
680
681 radio_conf_t conf = {
682 .name = NULL,
683 .host = NULL,
684 .port = 4532,
685 .type = RIG_TYPE_RX,
686 .ptt = 0,
687 .vfoUp = 0,
688 .vfoDown = 0,
689 .lo = 0.0,
690 .loup = 0.0,
691 .signal_aos = FALSE,
692 .signal_los = FALSE,
693 };
694
695 /* run rig conf editor */
696 sat_pref_rig_editor_run(&conf);
697
698 /* add new rig to the list */
699 if (conf.name != NULL)
700 {
701 liststore =
702 GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(riglist)));
703 gtk_list_store_append(liststore, &item);
704 gtk_list_store_set(liststore, &item,
705 RIG_LIST_COL_NAME, conf.name,
706 RIG_LIST_COL_HOST, conf.host,
707 RIG_LIST_COL_PORT, conf.port,
708 RIG_LIST_COL_TYPE, conf.type,
709 RIG_LIST_COL_PTT, conf.ptt,
710 RIG_LIST_COL_VFOUP, conf.vfoUp,
711 RIG_LIST_COL_VFODOWN, conf.vfoDown,
712 RIG_LIST_COL_LO, conf.lo,
713 RIG_LIST_COL_LOUP, conf.loup,
714 RIG_LIST_COL_SIGAOS, conf.signal_aos,
715 RIG_LIST_COL_SIGLOS, conf.signal_los, -1);
716
717 g_free(conf.name);
718
719 if (conf.host != NULL)
720 g_free(conf.host);
721 }
722 }
723
724 /**
725 * Create buttons.
726 *
727 * @param riglist The GtkTreeView widget containing the rig data.
728 * @return A button box containing the buttons.
729 *
730 * This function creates and initialises the three buttons below the rig list.
731 * The treeview widget is needed by the buttons when they are activated.
732 */
create_buttons(void)733 static GtkWidget *create_buttons(void)
734 {
735 GtkWidget *box;
736
737 /* add button */
738 addbutton = gtk_button_new_with_label(_("Add new"));
739 gtk_widget_set_tooltip_text(addbutton, _("Add a new radio to the list"));
740 g_signal_connect(addbutton, "clicked", G_CALLBACK(add_cb), NULL);
741
742 /* edit button */
743 editbutton = gtk_button_new_with_label(_("Edit"));
744 gtk_widget_set_tooltip_text(editbutton, _("Edit selected radio"));
745 g_signal_connect(editbutton, "clicked", G_CALLBACK(edit_cb), NULL);
746
747 /* delete button; don't forget to delete file.... */
748 delbutton = gtk_button_new_with_label(_("Delete"));
749 gtk_widget_set_tooltip_text(delbutton, _("Delete selected radio"));
750 g_signal_connect(delbutton, "clicked", G_CALLBACK(delete_cb), NULL);
751
752 /* vertical button box */
753 box = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
754 gtk_button_box_set_layout(GTK_BUTTON_BOX(box), GTK_BUTTONBOX_START);
755
756 gtk_container_add(GTK_CONTAINER(box), addbutton);
757 gtk_container_add(GTK_CONTAINER(box), editbutton);
758 gtk_container_add(GTK_CONTAINER(box), delbutton);
759
760 return box;
761 }
762
763 /* Create and initialise widgets for the radios tab. */
sat_pref_rig_create()764 GtkWidget *sat_pref_rig_create()
765 {
766 GtkWidget *vbox; /* vbox containing the list part and the details part */
767 GtkWidget *swin;
768
769 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
770 gtk_box_set_homogeneous(GTK_BOX(vbox), FALSE);
771 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
772
773 /* create qth list and pack into scrolled window */
774 create_rig_list();
775 swin = gtk_scrolled_window_new(NULL, NULL);
776 gtk_container_add(GTK_CONTAINER(swin), riglist);
777
778 gtk_box_pack_start(GTK_BOX(vbox), swin, TRUE, TRUE, 0);
779 gtk_box_pack_start(GTK_BOX(vbox), create_buttons(), FALSE, FALSE, 0);
780
781 return vbox;
782 }
783
784 /* User pressed cancel. Any changes to config must be cancelled. */
sat_pref_rig_cancel()785 void sat_pref_rig_cancel()
786 {
787 }
788
789 /**
790 * User pressed OK. Any changes should be stored in config.
791 *
792 * First, all .grc files are deleted, whereafter the radio configurations in
793 * the riglist are saved one by one.
794 */
sat_pref_rig_ok()795 void sat_pref_rig_ok()
796 {
797 GDir *dir = NULL; /* directory handle */
798 GError *error = NULL; /* error flag and info */
799 gchar *buff, *dirname;
800 const gchar *filename;
801 GtkTreeIter iter; /* new item added to the list store */
802 GtkTreeModel *model;
803 guint i, n;
804
805 radio_conf_t conf = {
806 .name = NULL,
807 .host = NULL,
808 .port = 4532,
809 .type = RIG_TYPE_RX,
810 .ptt = 0,
811 .vfoUp = 0,
812 .vfoDown = 0,
813 .lo = 0.0,
814 .loup = 0.0,
815 .signal_aos = FALSE,
816 .signal_los = FALSE
817 };
818
819 /* delete all .rig files */
820 dirname = get_hwconf_dir();
821
822 dir = g_dir_open(dirname, 0, &error);
823 if (dir)
824 {
825 /* read each .rig file */
826 while ((filename = g_dir_read_name(dir)))
827 {
828 if (g_str_has_suffix(filename, ".rig"))
829 {
830 buff = g_strconcat(dirname, G_DIR_SEPARATOR_S, filename, NULL);
831 if (g_remove(buff))
832 sat_log_log(SAT_LOG_LEVEL_ERROR,
833 _("%s: Failed to remove %s"), __func__, buff);
834 g_free(buff);
835 }
836 }
837 }
838
839 g_free(dirname);
840 g_dir_close(dir);
841
842 /* create new .rig files for the radios in the riglist */
843 model = gtk_tree_view_get_model(GTK_TREE_VIEW(riglist));
844 n = gtk_tree_model_iter_n_children(model, NULL);
845 for (i = 0; i < n; i++)
846 {
847 /* get radio conf */
848 if (gtk_tree_model_iter_nth_child(model, &iter, NULL, i))
849 {
850 /* store conf */
851 gtk_tree_model_get(model, &iter,
852 RIG_LIST_COL_NAME, &conf.name,
853 RIG_LIST_COL_HOST, &conf.host,
854 RIG_LIST_COL_PORT, &conf.port,
855 RIG_LIST_COL_TYPE, &conf.type,
856 RIG_LIST_COL_PTT, &conf.ptt,
857 RIG_LIST_COL_VFOUP, &conf.vfoUp,
858 RIG_LIST_COL_VFODOWN, &conf.vfoDown,
859 RIG_LIST_COL_LO, &conf.lo,
860 RIG_LIST_COL_LOUP, &conf.loup,
861 RIG_LIST_COL_SIGAOS, &conf.signal_aos,
862 RIG_LIST_COL_SIGLOS, &conf.signal_los, -1);
863 radio_conf_save(&conf);
864
865 /* free conf buffer */
866 if (conf.name)
867 g_free(conf.name);
868
869 if (conf.host)
870 g_free(conf.host);
871 }
872 else
873 {
874 sat_log_log(SAT_LOG_LEVEL_ERROR,
875 _("%s: Failed to get RIG %s"), __func__, i);
876 }
877 }
878
879 }
880