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