/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* Gpredict: Real-time satellite tracking and orbit prediction program Copyright (C) 2001-2007 Alexandru Csete, OZ9AEC. Authors: Alexandru Csete Comments, questions and bugreports should be submitted via http://sourceforge.net/projects/groundstation/ More details can be found at the project home page: http://groundstation.sourceforge.net/ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, visit http://www.fsf.org/ */ #include #include #include #include #ifdef HAVE_CONFIG_H # include #endif #include "gpredict-utils.h" #include "loc-tree.h" #include "sat-cfg.h" #include "sat-log.h" #include "locator.h" #include "gtk-sat-data.h" #include "qth-editor.h" /** \brief Symbolic refs to be used when calling select_location in order * to determine which mode the selection should run in, ie. * select location or select weather station. */ enum { SELECTION_MODE_LOC = 1, SELECTION_MODE_WX = 2 }; extern GtkWidget *window; /* dialog window defined in sat-pref.c */ static GtkWidget *create_editor_widgets (qth_t *qth); static void update_widgets (qth_t *qth); static void clear_widgets (void); static void name_changed (GtkWidget *widget, gpointer data); static void select_location (GtkWidget *widget, gpointer data); static gboolean apply_changes (qth_t *qth); static void latlon_changed (GtkWidget *widget, gpointer data); static void qra_changed (GtkEntry *entry, gpointer data); /* private widgets */ static GtkWidget *dialog; /* dialog window */ static GtkWidget *name; /* QTH name */ static GtkWidget *location; /* QTH location */ static GtkWidget *desc; /* QTH description */ static GtkWidget *lat,*lon,*alt; /* LAT, LON and ALT */ static GtkWidget *ns,*ew; static GtkWidget *qra; /* QRA locator */ static gulong latsigid,lonsigid,nssigid,ewsigid,qrasigid; static GtkWidget *wx; /* weather station */ /** \brief Create and run QTH editor. * \param qth Pointer to a qth_t structure where QTH data should be stored. * \param parent The parent dialog window. * \return GTK_RESPONSE_OK if the new QTH has been saved, GTK_RESPONSE_CANCEL * otherwise (e.g. user cancelled the operation. * * The QTH editor is a dialog window containing widgets that can be used to * edit an existing QTH or create a new one. If qth->name != NULL the function * will run in edit mode, i.e. preload the widgets with values from qth, otherwise * it will create empty widgets. * * To see the widget in action click on the "+" button in either the "New Module" * or "Configure Module" dialog. * * \bug Edit mode doesn't really works, that is, it does, but probably leaks memory * because I can't free existing data in qth_t */ GtkResponseType qth_editor_run (qth_t *qth, GtkWindow *parent) { gint response; gboolean finished = FALSE; /* crate dialog and add contents */ dialog = gtk_dialog_new_with_buttons (_("Edit ground station data"), parent, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CLEAR, GTK_RESPONSE_REJECT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); /* disable OK button to begin with */ gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE); gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), create_editor_widgets (qth)); /* this hacky-thing is to keep the dialog running in case the CLEAR button is plressed. OK and CANCEL will exit the loop */ while (!finished) { response = gtk_dialog_run (GTK_DIALOG (dialog)); switch (response) { /* OK */ case GTK_RESPONSE_OK: if (apply_changes (qth)) { finished = TRUE; } else { /* and error occured; try again */ GtkWidget *errd; errd = gtk_message_dialog_new (parent, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("An error occurred while trying to save\n"\ "ground station data to %s.qth!\n"\ "Please try again using a different name."), qth->name); gtk_dialog_run (GTK_DIALOG (errd)); gtk_widget_destroy (errd); finished = FALSE; } break; /* CLEAR */ case GTK_RESPONSE_REJECT: clear_widgets (); break; /* Everything else is considered CANCEL */ default: finished = TRUE; break; } } gtk_widget_destroy (dialog); return response; } /** \brief Create and initialise widgets */ static GtkWidget * create_editor_widgets (qth_t *qth) { GtkWidget *table; GtkWidget *label; GtkTooltips *tooltips; GtkWidget *locbut; GtkWidget *wxbut; table = gtk_table_new (9, 4, FALSE); gtk_container_set_border_width (GTK_CONTAINER (table), 5); gtk_table_set_col_spacings (GTK_TABLE (table), 5); gtk_table_set_row_spacings (GTK_TABLE (table), 5); /* QTH name */ label = gtk_label_new (_("Name")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 0, 1); name = gtk_entry_new (); gtk_entry_set_max_length (GTK_ENTRY (name), 25); tooltips = gtk_tooltips_new (); gtk_tooltips_set_tip (tooltips, name, _("Enter a short name for this ground station, e.g. callsign.\n"\ "Allowed charachters: 0..9, a..z, A..Z, - and _"), _("The name will be used to identify the ground station "\ "when it is presented to the user. Maximum allowed length "\ "is 25 charachters.")); gtk_table_attach_defaults (GTK_TABLE (table), name, 1, 4, 0, 1); /* attach changed signal so that we can enable OK button when a proper name has been entered */ g_signal_connect (name, "changed", G_CALLBACK (name_changed), NULL); /* QTH description */ label = gtk_label_new (_("Description")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 1, 2); desc = gtk_entry_new (); gtk_entry_set_max_length (GTK_ENTRY (desc), 256); tooltips = gtk_tooltips_new (); gtk_tooltips_set_tip (tooltips, desc, _("Enter an optional description for this ground station."), _("The description for the ground station can be used as additional "\ "information. It may be included when generating reports. "\ "The maximum length for the description is 256 characters.")); gtk_table_attach_defaults (GTK_TABLE (table), desc, 1, 4, 1, 2); /* location */ label = gtk_label_new (_("Location")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 2, 3); location = gtk_entry_new (); gtk_entry_set_max_length (GTK_ENTRY (location), 50); tooltips = gtk_tooltips_new (); gtk_tooltips_set_tip (tooltips, location, _("Optional location of the ground station, fx. Copenhagen, Denmark."), NULL); gtk_table_attach_defaults (GTK_TABLE (table), location, 1, 3, 2, 3); locbut = gpredict_hstock_button (GTK_STOCK_INDEX, _("Select"), _("Select a predefined location from a list.")); g_signal_connect (locbut, "clicked", G_CALLBACK (select_location), GUINT_TO_POINTER (SELECTION_MODE_LOC)); gtk_table_attach_defaults (GTK_TABLE (table), locbut, 3, 4, 2, 3); /* latitude */ label = gtk_label_new (_("Latitude (\302\260)")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 3, 4); lat = gtk_spin_button_new_with_range (0.00, 90.00, 0.0001); gtk_spin_button_set_increments (GTK_SPIN_BUTTON (lat), 0.01, 1.0); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (lat), TRUE); gtk_spin_button_set_digits (GTK_SPIN_BUTTON (lat), 4); tooltips = gtk_tooltips_new (); gtk_tooltips_set_tip (tooltips, lat, _("Select the latitude of the ground station in decimal degrees."), NULL); gtk_table_attach_defaults (GTK_TABLE (table), lat, 1, 2, 3, 4); ns = gtk_combo_box_new_text (); gtk_combo_box_append_text (GTK_COMBO_BOX (ns), _("North")); gtk_combo_box_append_text (GTK_COMBO_BOX (ns), _("South")); gtk_combo_box_set_active (GTK_COMBO_BOX (ns), 0); /*** FIXME tooltips */ gtk_table_attach_defaults (GTK_TABLE (table), ns, 2, 3, 3, 4); /* longitude */ label = gtk_label_new (_("Longitude (\302\260)")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 4, 5); lon = gtk_spin_button_new_with_range (0.00, 180.00, 0.0001); gtk_spin_button_set_increments (GTK_SPIN_BUTTON (lon), 0.01, 1.0); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (lon), TRUE); gtk_spin_button_set_digits (GTK_SPIN_BUTTON (lon), 4); gtk_tooltips_set_tip (tooltips, lon, _("Select the longitude of the ground station in decimal degrees."), NULL); gtk_table_attach_defaults (GTK_TABLE (table), lon, 1, 2, 4, 5); ew = gtk_combo_box_new_text (); gtk_combo_box_append_text (GTK_COMBO_BOX (ew), _("East")); gtk_combo_box_append_text (GTK_COMBO_BOX (ew), _("West")); gtk_combo_box_set_active (GTK_COMBO_BOX (ew), 0); /*** FIXME tooltips */ gtk_table_attach_defaults (GTK_TABLE (table), ew, 2, 3, 4, 5); /* connect lat/lon spinners and combos to callback remember signal id so that we can block signals while doing automatic cross-updates */ latsigid = g_signal_connect (lat, "value-changed", G_CALLBACK (latlon_changed), NULL); lonsigid = g_signal_connect (lon, "value-changed", G_CALLBACK (latlon_changed), NULL); nssigid = g_signal_connect (ns, "changed", G_CALLBACK (latlon_changed), NULL); ewsigid = g_signal_connect (ew, "changed", G_CALLBACK (latlon_changed), NULL); /* QRA locator */ label = gtk_label_new (_("Locator")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 5, 6); qra = gtk_entry_new (); gtk_entry_set_max_length (GTK_ENTRY (qra), 6); tooltips = gtk_tooltips_new (); gtk_tooltips_set_tip (tooltips, qra, _("Maidenhead locator grid."), NULL); gtk_table_attach_defaults (GTK_TABLE (table), qra, 1, 2, 5, 6); qrasigid = g_signal_connect (qra, "changed", G_CALLBACK (qra_changed), NULL); /* altitude */ label = gtk_label_new (_("Altitude")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 6, 7); alt = gtk_spin_button_new_with_range (0, 5000, 1); gtk_spin_button_set_increments (GTK_SPIN_BUTTON (alt), 1, 100); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (alt), TRUE); gtk_tooltips_set_tip (tooltips, alt, _("Select the altitude of the ground station in meters or feet "\ "depending on your settings"), NULL); gtk_table_attach_defaults (GTK_TABLE (table), alt, 1, 2, 6, 7); if (sat_cfg_get_bool (SAT_CFG_BOOL_USE_IMPERIAL)) { label = gtk_label_new (_("ft asl")); } else { label = gtk_label_new (_("m asl")); } gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach_defaults (GTK_TABLE (table), label, 2, 3, 6, 7); /* weather station */ label = gtk_label_new (_("Weather St")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 7, 8); wx = gtk_entry_new (); gtk_entry_set_max_length (GTK_ENTRY (wx), 4); tooltips = gtk_tooltips_new (); gtk_tooltips_set_tip (tooltips, wx, _("Four letter code for weather station"), NULL); gtk_table_attach_defaults (GTK_TABLE (table), wx, 1, 3, 7, 8); wxbut = gpredict_hstock_button (GTK_STOCK_INDEX, _("Select"), _("Select a predefined weather station from a list.")); g_signal_connect (wxbut, "clicked", G_CALLBACK (select_location), GUINT_TO_POINTER (SELECTION_MODE_WX)); gtk_table_attach_defaults (GTK_TABLE (table), wxbut, 3, 4, 7, 8); if (qth->name != NULL) update_widgets (qth); gtk_widget_show_all (table); return table; } /** \brief Update widgets from the currently selected row in the treeview */ static void update_widgets (qth_t *qth) { if (qth->name != NULL) gtk_entry_set_text (GTK_ENTRY (name), qth->name); if (qth->loc != NULL) { gtk_entry_set_text (GTK_ENTRY (location), qth->loc); } if (qth->desc != NULL) { gtk_entry_set_text (GTK_ENTRY (desc), qth->desc); } if (qth->wx != NULL) { gtk_entry_set_text (GTK_ENTRY (wx), qth->wx); } if (qth->lat < 0.00) gtk_combo_box_set_active (GTK_COMBO_BOX (ns), 1); else gtk_combo_box_set_active (GTK_COMBO_BOX (ns), 0); gtk_spin_button_set_value (GTK_SPIN_BUTTON (lat), fabs (qth->lat)); if (qth->lon < 0.00) gtk_combo_box_set_active (GTK_COMBO_BOX (ew), 1); else gtk_combo_box_set_active (GTK_COMBO_BOX (ew), 0); gtk_spin_button_set_value (GTK_SPIN_BUTTON (lon), fabs (qth->lon)); gtk_spin_button_set_value (GTK_SPIN_BUTTON (alt), qth->alt); sat_log_log (SAT_LOG_LEVEL_DEBUG, _("%s:%d: Loaded %s for editing:\n"\ "LAT:%.2f LON:%.2f ALT:%d"), __FILE__, __LINE__, (qth->name != NULL) ? qth->name : "???", qth->lat, qth->lon, qth->alt); } /** \brief Clear the contents of all widgets. * * This function is usually called when the user clicks on the CLEAR button * */ static void clear_widgets () { gtk_entry_set_text (GTK_ENTRY (name), ""); gtk_entry_set_text (GTK_ENTRY (location), ""); gtk_entry_set_text (GTK_ENTRY (desc), ""); gtk_entry_set_text (GTK_ENTRY (wx), ""); gtk_spin_button_set_value (GTK_SPIN_BUTTON (lat), 0.0); gtk_spin_button_set_value (GTK_SPIN_BUTTON (lon), 0.0); gtk_spin_button_set_value (GTK_SPIN_BUTTON (alt), 0); gtk_entry_set_text (GTK_ENTRY (qra), ""); } /** \brief Apply changes. * \return TRUE if things are ok, FALSE otherwise. * * This function is usually called when the user clicks the OK button. */ static gboolean apply_changes (qth_t *qth) { const gchar *qthname = NULL; const gchar *qthloc = NULL; const gchar *qthdesc = NULL; const gchar *qthwx = NULL; const gchar *qthqra= NULL; gdouble qthlat; gdouble qthlon; guint qthalt; gchar *fname; gboolean retcode; /* get values from widgets */ qthname = gtk_entry_get_text (GTK_ENTRY (name)); qthloc = gtk_entry_get_text (GTK_ENTRY (location)); qthdesc = gtk_entry_get_text (GTK_ENTRY (desc)); qthwx = gtk_entry_get_text (GTK_ENTRY (wx)); qthlat = gtk_spin_button_get_value (GTK_SPIN_BUTTON (lat)); if (gtk_combo_box_get_active (GTK_COMBO_BOX (ns))) qthlat = -qthlat; qthlon = gtk_spin_button_get_value (GTK_SPIN_BUTTON (lon)); if (gtk_combo_box_get_active (GTK_COMBO_BOX (ew))) qthlon = -qthlon; qthalt = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (alt)); qthqra = gtk_entry_get_text (GTK_ENTRY (qra)); /* clear qth struct if not empty */ /* if (qth->name != NULL) */ /* g_free (qth->name); */ /* if (qth->loc != NULL) */ /* g_free (qth->loc); */ /* if (qth->desc != NULL) */ /* g_free (qth->desc); */ /* if (qth->wx != NULL) */ /* g_free (qth->wx); */ /* if (qth->qra != NULL) */ /* g_free (qth->qra); */ /* if (qth->data != NULL) */ /* g_key_file_free (qth->data); */ /* copy new values to qth struct */ qth->name = g_strdup (qthname); if (qthloc != NULL) qth->loc = g_strdup (qthloc); if (qthdesc != NULL) qth->desc = g_strdup (qthdesc); if (qthwx != NULL) qth->wx = g_strdup (qthwx); if (qthqra != NULL) qth->qra = g_strdup (qthqra); qth->lat = qthlat; qth->lon = qthlon; qth->alt = qthalt; /* store values to disc */ fname = g_strconcat (g_get_home_dir (), G_DIR_SEPARATOR_S, ".gpredict2", G_DIR_SEPARATOR_S, qth->name, ".qth", NULL); retcode = gtk_sat_data_save_qth (fname, qth); g_free (fname); return retcode; } /** \brief Manage name changes. * * This function is called when the contents of the name entry changes. * The primary purpose of this function is to check whether the char length * of the name is greater than zero, if yes enable the OK button of the dialog. */ static void name_changed (GtkWidget *widget, gpointer data) { const gchar *text; gchar *entry, *end, *j; gint len, pos; /* step 1: ensure that only valid characters are entered (stolen from xlog, tnx pg4i) */ entry = gtk_editable_get_chars (GTK_EDITABLE (widget), 0, -1); if ((len = g_utf8_strlen (entry, -1)) > 0) { end = entry + g_utf8_strlen (entry, -1); for (j = entry; j < end; ++j) { switch (*j) { case '0' ... '9': case 'a' ... 'z': case 'A' ... 'Z': case '-': case '_': break; default: gdk_beep (); pos = gtk_editable_get_position (GTK_EDITABLE (widget)); gtk_editable_delete_text (GTK_EDITABLE (widget), pos, pos+1); break; } } } /* step 2: if name seems all right, enable OK button */ text = gtk_entry_get_text (GTK_ENTRY (widget)); if (g_utf8_strlen (text, -1) > 0) { gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE); } else { gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE); } } /** \brief Manage SELECT button clicks. * * This function is called when the user clicks on one of the SELECT buttons. * the data parameter contains information about which button has been clicked. */ static void select_location (GtkWidget *widget, gpointer data) { guint mode = GPOINTER_TO_UINT (data); guint flags; gchar *qthloc; gchar *qthwx; gfloat qthlat; gfloat qthlon; guint qthalt; gboolean selected = FALSE; switch (mode) { /* We distinguish only between WX mode and "everything else". Although a value != 1 or 2 is definitely a bug, we need to have some sensible fall-back. */ case SELECTION_MODE_WX: flags = TREE_COL_FLAG_NAME | TREE_COL_FLAG_WX; break; default: flags = TREE_COL_FLAG_NAME | TREE_COL_FLAG_LAT | TREE_COL_FLAG_LON | TREE_COL_FLAG_ALT | TREE_COL_FLAG_WX; mode = SELECTION_MODE_LOC; break; } selected = loc_tree_create (NULL, flags, &qthloc, &qthlat, &qthlon, &qthalt, &qthwx); if (selected) { /* update widgets */ switch (mode) { case SELECTION_MODE_WX: gtk_entry_set_text (GTK_ENTRY (wx), qthwx); break; case SELECTION_MODE_LOC: gtk_entry_set_text (GTK_ENTRY (location), qthloc); gtk_entry_set_text (GTK_ENTRY (wx), qthwx); gtk_spin_button_set_value (GTK_SPIN_BUTTON (lat), fabs (qthlat)); if (qthlat < 0.00) gtk_combo_box_set_active (GTK_COMBO_BOX (ns), 1); else gtk_combo_box_set_active (GTK_COMBO_BOX (ns), 0); gtk_spin_button_set_value (GTK_SPIN_BUTTON (lon), fabs (qthlon)); if (qthlon < 0.00) gtk_combo_box_set_active (GTK_COMBO_BOX (ew), 1); else gtk_combo_box_set_active (GTK_COMBO_BOX (ew), 0); gtk_spin_button_set_value (GTK_SPIN_BUTTON (alt), qthalt); break; default: /*** FIXME: add some error reporting */ break; } /* free some memory */ g_free (qthloc); g_free (qthwx); } /* else do nothing; we are finished */ } /** \brief Manage coordinate changes. * * This function is called when the qth coordinates change. The change can * be either one of the spin buttons or the combo boxes. It reads the * coordinates and the calculates the new Maidenhead locator square. */ static void latlon_changed (GtkWidget *widget, gpointer data) { gchar *locator; gint retcode; gdouble latf,lonf; locator = g_try_malloc (7); /* no need to check locator != NULL, since hamlib func will do it for us and return RIGEINVAL */ lonf = gtk_spin_button_get_value (GTK_SPIN_BUTTON (lon)); latf = gtk_spin_button_get_value (GTK_SPIN_BUTTON (lat)); /* set the correct sign */ if (gtk_combo_box_get_active (GTK_COMBO_BOX (ns))) { /* index 1 => South */ latf = -latf; } if (gtk_combo_box_get_active (GTK_COMBO_BOX (ew))) { /* index 1 => Wesr */ lonf = -lonf; } retcode = longlat2locator (lonf, latf, locator, 3); if (retcode == RIG_OK) { /* debug message */ sat_log_log (SAT_LOG_LEVEL_DEBUG, _("%s:%s: %.2f %.2f => %s"), __FILE__, __FUNCTION__, gtk_spin_button_get_value (GTK_SPIN_BUTTON (lon)), gtk_spin_button_get_value (GTK_SPIN_BUTTON (lat)), locator); g_signal_handler_block (qra, qrasigid); gtk_entry_set_text (GTK_ENTRY (qra), locator); g_signal_handler_unblock (qra, qrasigid); } else { /* send an error message and don't update */ sat_log_log (SAT_LOG_LEVEL_ERROR, _("%s:%d: Error converting lon/lat to locator"), __FILE__, __LINE__); } if (locator) g_free (locator); } /** \brief Manage locator changes. * * This function is called when the Maidenhead locator is changed. * It will calculate the new coordinates and update the spin butrtons and * the combo boxes. */ static void qra_changed (GtkEntry *entry, gpointer data) { gint retcode; gdouble latf,lonf; gchar *msg; retcode = locator2longlat (&lonf, &latf, gtk_entry_get_text (GTK_ENTRY (qra))); if (retcode == RIG_OK) { /* debug message */ sat_log_log (SAT_LOG_LEVEL_DEBUG, _("%s:%s: %s => %.2f %.2f"), __FILE__, __FUNCTION__, gtk_entry_get_text (GTK_ENTRY (qra)), lonf, latf); /* block signal emissions for lat/lon widgets */ g_signal_handler_block (lat, latsigid); g_signal_handler_block (lon, lonsigid); g_signal_handler_block (ns, nssigid); g_signal_handler_block (ew, ewsigid); g_signal_handler_block (qra, qrasigid); /* update widgets */ if (latf < 0.00) gtk_combo_box_set_active (GTK_COMBO_BOX (ns), 1); else gtk_combo_box_set_active (GTK_COMBO_BOX (ns), 0); if (lonf < 0.00) gtk_combo_box_set_active (GTK_COMBO_BOX (ew), 1); else gtk_combo_box_set_active (GTK_COMBO_BOX (ew), 0); gtk_spin_button_set_value (GTK_SPIN_BUTTON (lat), fabs (latf)); gtk_spin_button_set_value (GTK_SPIN_BUTTON (lon), fabs (lonf)); /* make sure text is upper case */ msg = g_ascii_strup (gtk_entry_get_text (GTK_ENTRY (qra)), -1); gtk_entry_set_text (GTK_ENTRY (qra), msg); g_free (msg); /* unblock signal emissions */ g_signal_handler_unblock (lat, latsigid); g_signal_handler_unblock (lon, lonsigid); g_signal_handler_unblock (ns, nssigid); g_signal_handler_unblock (ew, ewsigid); g_signal_handler_unblock (qra, qrasigid); } else { /* send an error message and don't update */ sat_log_log (SAT_LOG_LEVEL_ERROR, _("%s:%d: Invalid locator: %s"), __FILE__, __LINE__, gtk_entry_get_text (GTK_ENTRY (qra))); } }