/** \brief Get thumbnail icon filename from selection ID.
  * \param sel The ID of the predefined layout or PREDEF_NUM-1 for custom.
  * \return A newly allocated string containing the full path of the icon.
  *
  * This function generates an icon file name from the ID of a predefined
  * layout. PREDEF_NUM-1 corresponds to the last entry in predef_layout[][],
  * which is the custom layout. The returned string should be freed when no
  * longer needed.
  *
  * The function checks that sel is within valid range (0...PREDEF_NUM-1). If
  * sel is outside the range, the custom layout icon is returned.
  */
static gchar *thumb_file_from_sel (guint sel)
{
    gchar *fname;

    if (sel < PREDEF_NUM) {
        fname = icon_file_name (predef_layout[sel][2]);
    }
    else {
        fname = icon_file_name (predef_layout[PREDEF_NUM-1][2]);
    }

    return fname;
}
/** \brief Invoke Sky-at-glance.
 *
 * This function is a shortcut to the sky at glance function
 * in that it will make the predictions with the satellites
 * tracked in the current module.
 */
static void sky_at_glance_cb (GtkWidget *menuitem, gpointer data)
{
    GtkSatModule *module = GTK_SAT_MODULE (data);
    //GtkWidget    *skg;
    //GtkWidget    *window;
    gchar        *buff;

    (void) menuitem; /* avoid unused parameter compiler warning */

    /* if module is busy wait until done then go on */
    g_mutex_lock(&module->busy);


    if (module->skgwin != NULL) {
        /* there is already a sky at glance for this module */
        gtk_window_present (GTK_WINDOW (module->skgwin));
        g_mutex_unlock(&module->busy);

        return;
    }


    /* create window */
    module->skgwin = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    buff = g_strdup_printf (_("The sky at a glance (%s)"), module->name);
    gtk_window_set_title (GTK_WINDOW (module->skgwin), buff);
    g_free (buff);
    g_signal_connect (G_OBJECT (module->skgwin), "delete_event", G_CALLBACK (window_delete), NULL);
    g_signal_connect (G_OBJECT (module->skgwin), "destroy", G_CALLBACK (destroy_skg), module);

    /* window icon */
    buff = icon_file_name ("gpredict-planner.png");
    gtk_window_set_icon_from_file (GTK_WINDOW (module->skgwin), buff, NULL);
    g_free (buff);


    /* create sky at a glance widget */  
    if (sat_cfg_get_bool (SAT_CFG_BOOL_PRED_USE_REAL_T0)) {
        module->skg = gtk_sky_glance_new (module->satellites, module->qth, 0.0);
    }
    else {
        module->skg = gtk_sky_glance_new (module->satellites, module->qth, module->tmgCdnum);
    }

    /* store time at which GtkSkyGlance has been created */
    module->lastSkgUpd = module->tmgCdnum;

    gtk_container_set_border_width (GTK_CONTAINER (module->skgwin), 10);
    gtk_container_add (GTK_CONTAINER (module->skgwin), module->skg);

    gtk_widget_show_all (module->skgwin);

    g_mutex_unlock(&module->busy);

}
/** \brief Open Radio control window. 
 * \param menuitem The menuitem that was selected.
 * \param data Pointer the GtkSatModule.
 */
static void rigctrl_cb (GtkWidget *menuitem, gpointer data)
{
    GtkSatModule *module = GTK_SAT_MODULE (data);
    gchar *buff;
    
    (void) menuitem; /* avoid unused parameter compiler warning */
    
    if (module->rigctrlwin != NULL) {
        /* there is already a roto controller for this module */
        gtk_window_present (GTK_WINDOW (module->rigctrlwin));
        return;
    }

    module->rigctrl = gtk_rig_ctrl_new (module);
    
    if (module->rigctrl == NULL) {
        /* gtk_rot_ctrl_new returned NULL becasue no radios are configured */
        GtkWidget *dialog;
        dialog = gtk_message_dialog_new (GTK_WINDOW (app),
                                         GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
                                         GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
                                         _("You have no radio configuration!\n"\
                                           "Please configure a radio first.")
                                         );
        g_signal_connect_swapped (dialog, "response", 
                                  G_CALLBACK (gtk_widget_destroy), dialog);
        gtk_window_set_title (GTK_WINDOW (dialog), _("ERROR"));
        gtk_widget_show_all (dialog);
        
        return;
    }
    
    /* create a window */
    module->rigctrlwin = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    buff = g_strdup_printf (_("Gpredict Radio Control: %s"), module->name);
    gtk_window_set_title (GTK_WINDOW (module->rigctrlwin), buff);
    g_free (buff);
    g_signal_connect (G_OBJECT (module->rigctrlwin), "delete_event",
                      G_CALLBACK (window_delete), NULL);
    g_signal_connect (G_OBJECT (module->rigctrlwin), "destroy",
                      G_CALLBACK (destroy_rigctrl), module);

    /* window icon */
    buff = icon_file_name ("gpredict-oscilloscope.png");
    gtk_window_set_icon_from_file (GTK_WINDOW (module->rigctrlwin), buff, NULL);
    g_free (buff);
    
    gtk_container_add (GTK_CONTAINER (module->rigctrlwin), module->rigctrl);
    
    gtk_widget_show_all (module->rigctrlwin);

}
/** \brief Create and initialise time controller widgets.
 *  \param module The parent GtkSatModule
 *
 */
void tmg_create (GtkSatModule *mod)
{
    GtkWidget   *vbox, *hbox, *table;
    GtkWidget   *image;
    GtkWidget   *label;
    gchar       *title;
    gchar       *buff;


    /* make sure controller is not already active */
    if (mod->tmgActive) {
        sat_log_log (SAT_LOG_LEVEL_INFO,
                     _("%s: Time Controller for %s is already active"),
                     __FUNCTION__, mod->name);

        /* try to make window visible in case it is covered
                   by something else */
        gtk_window_present (GTK_WINDOW (mod->tmgWin));

        return;
    }

    /* create hbox containing the controls
       the controls are implemented as radiobuttons in order
       to inherit the mutual exclusion behaviour
    */
    hbox = gtk_hbox_new (FALSE, 0);

    
    /* FWD */
    mod->tmgFwd = gtk_radio_button_new (NULL);
    gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (mod->tmgFwd), FALSE);
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mod->tmgFwd), TRUE);
    image = gtk_image_new_from_stock (GTK_STOCK_MEDIA_FORWARD, GTK_ICON_SIZE_BUTTON);
    gtk_container_add (GTK_CONTAINER (mod->tmgFwd), image);
    gtk_widget_set_tooltip_text (mod->tmgFwd, _("Play forward"));
    g_signal_connect (mod->tmgFwd, "toggled", G_CALLBACK (tmg_fwd), mod);
    gtk_box_pack_end (GTK_BOX (hbox), mod->tmgFwd, FALSE, FALSE, 0);

    /* STOP */
    mod->tmgStop = gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (mod->tmgFwd));
    gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (mod->tmgStop), FALSE);
    image = gtk_image_new_from_stock (GTK_STOCK_MEDIA_PAUSE, GTK_ICON_SIZE_BUTTON);
    gtk_container_add (GTK_CONTAINER (mod->tmgStop), image);
    gtk_widget_set_tooltip_text (mod->tmgStop, _("Stop"));
    g_signal_connect (mod->tmgStop, "toggled", G_CALLBACK (tmg_stop), mod);
    gtk_box_pack_end (GTK_BOX (hbox), mod->tmgStop, FALSE, FALSE, 0);

    /* BWD */
    mod->tmgBwd = gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (mod->tmgFwd));
    gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (mod->tmgBwd), FALSE);
    image = gtk_image_new_from_stock (GTK_STOCK_MEDIA_REWIND, GTK_ICON_SIZE_BUTTON);
    gtk_container_add (GTK_CONTAINER (mod->tmgBwd), image);
    gtk_widget_set_tooltip_text (mod->tmgBwd, _("Play backwards"));
    g_signal_connect (mod->tmgBwd, "toggled", G_CALLBACK (tmg_bwd), mod);
    gtk_box_pack_end (GTK_BOX (hbox), mod->tmgBwd, FALSE, FALSE, 0);

    /* reset time */
    mod->tmgReset = gtk_button_new_with_label (_("Reset"));
    gtk_widget_set_tooltip_text (mod->tmgReset, _("Reset to current date and time"));
    g_signal_connect (mod->tmgReset, "clicked", G_CALLBACK (tmg_reset), mod);
    gtk_box_pack_end (GTK_BOX (hbox), mod->tmgReset, FALSE, FALSE, 10);

    /* status label */
    mod->tmgState = gtk_label_new (NULL);
    gtk_misc_set_alignment (GTK_MISC (mod->tmgState), 0.0, 0.5);
    gtk_label_set_markup (GTK_LABEL (mod->tmgState), _("<b>Real-Time</b>"));
    gtk_box_pack_start (GTK_BOX (hbox), mod->tmgState, TRUE, TRUE, 10);


    /* create table containing the date and time widgets */
    table = gtk_table_new (5, 3, FALSE);
    gtk_table_set_row_spacings (GTK_TABLE (table), 0);

    mod->tmgCal = gtk_calendar_new ();
    gtk_calendar_set_display_options (GTK_CALENDAR (mod->tmgCal),
                                      GTK_CALENDAR_SHOW_HEADING     |
                                      GTK_CALENDAR_SHOW_DAY_NAMES |
                                      GTK_CALENDAR_WEEK_START_MONDAY);
    g_signal_connect (mod->tmgCal, "day-selected",
                      G_CALLBACK (tmg_time_set), mod);
    gtk_table_attach (GTK_TABLE (table), mod->tmgCal,
                      0, 1, 0, 5, GTK_SHRINK, GTK_SHRINK,
                      0, 0);

    /* Time controllers.
       Note that the controllers for hours, minutes, and seconds have ranges;
       however, they can wrap around their limits in order to ensure a smooth
       and continuous control of the time
    */

    /* hour */
    label = gtk_label_new (_(" Hour:"));
    gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
    gtk_table_attach (GTK_TABLE (table), label,
                      1, 2, 0, 1, GTK_SHRINK, GTK_SHRINK, 5, 0);
    mod->tmgHour = gtk_spin_button_new_with_range (0, 23, 1);
    gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (mod->tmgHour), TRUE);
    gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (mod->tmgHour),
                                       GTK_UPDATE_IF_VALID);
    gtk_spin_button_set_digits (GTK_SPIN_BUTTON (mod->tmgHour), 0);
    gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (mod->tmgHour), TRUE);
    //FIXME gtk_spin_button_set_value (GTK_SPIN_BUTTON (mod->tmgHour), 2);
    gtk_widget_set_tooltip_text (mod->tmgHour,
                                 _("Use this control to set the hour"));
    g_signal_connect (mod->tmgHour, "value-changed",
                      G_CALLBACK (tmg_time_set), mod);
    g_signal_connect (mod->tmgHour, "wrapped", G_CALLBACK (tmg_hour_wrap), mod);
    gtk_table_attach (GTK_TABLE (table), mod->tmgHour,
                      2, 3, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0);

    /* minutes */
    label = gtk_label_new (_(" Min:"));
    gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
    gtk_table_attach (GTK_TABLE (table), label,
                      1, 2, 1, 2, GTK_SHRINK, GTK_SHRINK, 5, 0);
    mod->tmgMin = gtk_spin_button_new_with_range (0, 59, 1);
    gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (mod->tmgMin), TRUE);
    gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (mod->tmgMin),
                                       GTK_UPDATE_IF_VALID);
    gtk_spin_button_set_digits (GTK_SPIN_BUTTON (mod->tmgMin), 0);
    gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (mod->tmgMin), TRUE);
    //FIXME gtk_spin_button_set_value (GTK_SPIN_BUTTON (mod->tmgMin), 2);
    gtk_widget_set_tooltip_text (mod->tmgMin,
                                 _("Use this control to set the minutes"));
    g_signal_connect (mod->tmgMin, "value-changed",
                      G_CALLBACK (tmg_time_set), mod);
    g_signal_connect (mod->tmgMin, "wrapped", G_CALLBACK (tmg_min_wrap), mod);
    gtk_table_attach (GTK_TABLE (table), mod->tmgMin,
                      2, 3, 1, 2, GTK_SHRINK, GTK_SHRINK, 0, 0);

    /* seconds */
    label = gtk_label_new (_(" Sec:"));
    gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
    gtk_table_attach (GTK_TABLE (table), label,
                      1, 2, 2, 3, GTK_SHRINK, GTK_SHRINK, 5, 0);
    mod->tmgSec = gtk_spin_button_new_with_range (0, 59, 1);
    gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (mod->tmgSec), TRUE);
    gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (mod->tmgSec),
                                       GTK_UPDATE_IF_VALID);
    gtk_spin_button_set_digits (GTK_SPIN_BUTTON (mod->tmgSec), 0);
    gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (mod->tmgSec), TRUE);
    //FIXME gtk_spin_button_set_value (GTK_SPIN_BUTTON (mod->tmgSec), 2);
    gtk_widget_set_tooltip_text (mod->tmgSec,
                                 _("Use this control to set the seconds"));
    g_signal_connect (mod->tmgSec, "value-changed",
                      G_CALLBACK (tmg_time_set), mod);
    g_signal_connect (mod->tmgSec, "wrapped", G_CALLBACK (tmg_sec_wrap), mod);
    gtk_table_attach (GTK_TABLE (table), mod->tmgSec,
                      2, 3, 2, 3, GTK_SHRINK, GTK_SHRINK, 0, 0);

    /* milliseconds */
    label = gtk_label_new (_(" Msec:"));
    gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
    gtk_table_attach (GTK_TABLE (table), label,
                      1, 2, 3, 4, GTK_SHRINK, GTK_SHRINK, 5, 0);
    mod->tmgMsec = gtk_spin_button_new_with_range (0, 999, 1);
    gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (mod->tmgMsec), TRUE);
    gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (mod->tmgMsec),
                                       GTK_UPDATE_IF_VALID);
    gtk_spin_button_set_digits (GTK_SPIN_BUTTON (mod->tmgMsec), 0);
    gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (mod->tmgMsec), TRUE);
    //FIXME gtk_spin_button_set_value (GTK_SPIN_BUTTON (mod->tmgMsec), 2);
    gtk_widget_set_tooltip_text (mod->tmgMsec,
                                 _("Use this control to set the milliseconds"));
    g_signal_connect (mod->tmgMsec, "value-changed",
                      G_CALLBACK (tmg_time_set), mod);
    g_signal_connect (mod->tmgMsec, "wrapped", G_CALLBACK (tmg_msec_wrap), mod);
    gtk_table_attach (GTK_TABLE (table), mod->tmgMsec,
                      2, 3, 3, 4, GTK_SHRINK, GTK_SHRINK, 0, 0);

    /* time throttle */
    label = gtk_label_new (_("Throttle:"));
    gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
    gtk_table_attach (GTK_TABLE (table), label,
                      1, 2, 4, 5, GTK_SHRINK, GTK_SHRINK, 5, 0);
    mod->tmgFactor = gtk_spin_button_new_with_range (1, 100, 1);
    gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (mod->tmgFactor), TRUE);
    gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (mod->tmgFactor),
                                       GTK_UPDATE_IF_VALID);
    gtk_spin_button_set_digits (GTK_SPIN_BUTTON (mod->tmgFactor), 0);
    gtk_spin_button_set_value (GTK_SPIN_BUTTON (mod->tmgFactor), 1);
    gtk_widget_set_tooltip_text (mod->tmgFactor,
                                 _("Time throttle / compression factor"));
    g_signal_connect (mod->tmgFactor, "value-changed",
                      G_CALLBACK (tmg_throttle), mod);
    gtk_table_attach (GTK_TABLE (table), mod->tmgFactor,
                      2, 3, 4, 5, GTK_SHRINK, GTK_SHRINK, 0, 0);

    /* add slider */
    mod->tmgSlider = gtk_hscale_new_with_range (-0.1, +0.1, 0.0001);  // +/- 2.5 hr
    /*gtk_widget_set_tooltip_text (mod->tmgSlider,
                                 _("Drag the slider to change the time up to +/- 2.5 hours.\n"\
                                   "Resolution is ~ 8 seconds."));*/
    gtk_scale_set_draw_value (GTK_SCALE (mod->tmgSlider), FALSE);
    gtk_range_set_value (GTK_RANGE (mod->tmgSlider), 0.0);
    g_signal_connect (mod->tmgSlider, "value-changed",
                      G_CALLBACK (slider_moved), mod);


    /* create the vertical box */
    vbox = gtk_vbox_new (FALSE, 0);

    gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
    gtk_box_pack_start (GTK_BOX (vbox), mod->tmgSlider, FALSE, FALSE, 0);
    gtk_box_pack_start (GTK_BOX (vbox), gtk_hseparator_new(), FALSE, FALSE, 0);
    gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);


    /* create main window */
    mod->tmgWin = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    title = g_strconcat (_("Time Controller"), " / ", mod->name, NULL);
    gtk_window_set_title (GTK_WINDOW (mod->tmgWin), title);
    g_free (title);
    gtk_window_set_transient_for (GTK_WINDOW (mod->tmgWin),
                                  GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (mod))));
    g_signal_connect (G_OBJECT (mod->tmgWin), "delete_event",
                      G_CALLBACK (tmg_delete), mod);    
    g_signal_connect (G_OBJECT (mod->tmgWin), "destroy",
                      G_CALLBACK (tmg_destroy), mod);

    /* window icon */
    buff = icon_file_name ("gpredict-clock.png");
    gtk_window_set_icon_from_file (GTK_WINDOW (mod->tmgWin), buff, NULL);
    g_free (buff);

    gtk_container_add (GTK_CONTAINER (mod->tmgWin), vbox);
    gtk_widget_show_all (mod->tmgWin);

    mod->tmgActive = TRUE;

    sat_log_log (SAT_LOG_LEVEL_INFO,
                 _("%s: Time Controller for %s launched"),
                 __FUNCTION__, mod->name);
}
Exemple #5
0
/*
 * Create a module window.
 *
 * This function is used to create a module window when opening modules
 * that should not be packed into the notebook.
 */
static void create_module_window(GtkWidget * module)
{
    gint            w, h;
    gchar          *icon;       /* icon file name */
    gchar          *title;      /* window title */
    GtkAllocation   aloc;

    gtk_widget_get_allocation(module, &aloc);
    /* get stored size; use size from main window if size not explicitly stoed */
    if (g_key_file_has_key(GTK_SAT_MODULE(module)->cfgdata,
                           MOD_CFG_GLOBAL_SECTION, MOD_CFG_WIN_WIDTH, NULL))
    {
        w = g_key_file_get_integer(GTK_SAT_MODULE(module)->cfgdata,
                                   MOD_CFG_GLOBAL_SECTION, MOD_CFG_WIN_WIDTH,
                                   NULL);
    }
    else
    {
        w = aloc.width;
    }
    if (g_key_file_has_key(GTK_SAT_MODULE(module)->cfgdata,
                           MOD_CFG_GLOBAL_SECTION, MOD_CFG_WIN_HEIGHT, NULL))
    {
        h = g_key_file_get_integer(GTK_SAT_MODULE(module)->cfgdata,
                                   MOD_CFG_GLOBAL_SECTION, MOD_CFG_WIN_HEIGHT,
                                   NULL);
    }
    else
    {
        h = aloc.height;
    }

    /* create window */
    GTK_SAT_MODULE(module)->win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    title = g_strconcat(_("GPREDICT: "),
                        GTK_SAT_MODULE(module)->name,
                        " (", GTK_SAT_MODULE(module)->qth->name, ")", NULL);
    gtk_window_set_title(GTK_WINDOW(GTK_SAT_MODULE(module)->win), title);
    g_free(title);
    gtk_window_set_default_size(GTK_WINDOW(GTK_SAT_MODULE(module)->win), w, h);
    g_signal_connect(G_OBJECT(GTK_SAT_MODULE(module)->win), "configure_event",
                     G_CALLBACK(module_window_config_cb), module);

    /* window icon */
    icon = icon_file_name("gpredict-icon.png");
    if (g_file_test(icon, G_FILE_TEST_EXISTS))
    {
        gtk_window_set_icon_from_file(GTK_WINDOW(GTK_SAT_MODULE(module)->win),
                                      icon, NULL);
    }
    g_free(icon);

    /* move window to stored position if requested by configuration */
    if (sat_cfg_get_bool(SAT_CFG_BOOL_MOD_WIN_POS) &&
        g_key_file_has_key(GTK_SAT_MODULE(module)->cfgdata,
                           MOD_CFG_GLOBAL_SECTION,
                           MOD_CFG_WIN_POS_X,
                           NULL) &&
        g_key_file_has_key(GTK_SAT_MODULE(module)->cfgdata,
                           MOD_CFG_GLOBAL_SECTION, MOD_CFG_WIN_POS_Y, NULL))
    {

        gtk_window_move(GTK_WINDOW(GTK_SAT_MODULE(module)->win),
                        g_key_file_get_integer(GTK_SAT_MODULE(module)->cfgdata,
                                               MOD_CFG_GLOBAL_SECTION,
                                               MOD_CFG_WIN_POS_X, NULL),
                        g_key_file_get_integer(GTK_SAT_MODULE(module)->cfgdata,
                                               MOD_CFG_GLOBAL_SECTION,
                                               MOD_CFG_WIN_POS_Y, NULL));

    }

    /* add module to window */
    gtk_container_add(GTK_CONTAINER(GTK_SAT_MODULE(module)->win), module);

    /* show window */
    gtk_widget_show_all(GTK_SAT_MODULE(module)->win);

    /* reparent time manager window if visible */
    if (GTK_SAT_MODULE(module)->tmgActive)
    {
        gtk_window_set_transient_for(GTK_WINDOW
                                     (GTK_SAT_MODULE(module)->tmgWin),
                                     GTK_WINDOW(GTK_SAT_MODULE(module)->win));
    }
}
/** \brief Show popup menu for a pass.
 *
 *
 */
void
pass_popup_menu_exec (qth_t *qth, pass_t *pass, GdkEventButton *event, GtkWidget *toplevel)
{
     GtkWidget        *menu;
     GtkWidget        *menuitem;
     GtkWidget        *image;
     gchar            *buff;


     menu = gtk_menu_new ();

     /* pass details */
     menuitem = gtk_image_menu_item_new_with_label (_("Show details"));
     image = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL,
                           GTK_ICON_SIZE_MENU);
     gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image);
     g_object_set_data (G_OBJECT (menuitem), "pass", pass);
     g_object_set_data (G_OBJECT (menuitem), "qth", qth);
     g_signal_connect (menuitem, "activate",
                 G_CALLBACK (show_pass_details),
                 toplevel);
     gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);
     
     /* separator */
     menuitem = gtk_separator_menu_item_new ();
     gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);


     /* Polar plot pass */
     menuitem = gtk_image_menu_item_new_with_label (_("Polar plot"));
     buff = icon_file_name ("gpredict-polar-small.png");
     image = gtk_image_new_from_file (buff);
     g_free (buff);
     gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image);
     g_object_set_data (G_OBJECT (menuitem), "pass", pass);
     g_object_set_data (G_OBJECT (menuitem), "qth", qth);
     g_signal_connect (menuitem, "activate",
                 G_CALLBACK (polar_plot_pass_details),
                 toplevel);
     gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);
     gtk_widget_set_sensitive (menuitem, FALSE);
          
     /* Az/El plot pass */
     menuitem = gtk_image_menu_item_new_with_label (_("Az/El plot"));
     buff = icon_file_name ("gpredict-azel-small.png");
     image = gtk_image_new_from_file (buff);
     g_free (buff);
     gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image);
     g_object_set_data (G_OBJECT (menuitem), "pass", pass);
     g_object_set_data (G_OBJECT (menuitem), "qth", qth);
     g_signal_connect (menuitem, "activate",
                 G_CALLBACK (azel_plot_pass_details),
                 toplevel);
     gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);
     gtk_widget_set_sensitive (menuitem, FALSE);


     gtk_widget_show_all (menu);

     /* Note: event can be NULL here when called from view_onPopupMenu;
      *  gdk_event_get_time() accepts a NULL argument */
     gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
               (event != NULL) ? event->button : 0,
               gdk_event_get_time ((GdkEvent*) event));
          

}
/** \brief Create and run GtkSatModule popup menu.
 *  \param module The module that should have the popup menu attached to it.
 *
 * This function ctreates and executes a popup menu that is related to a
 * GtkSatModule widget. The module must be a valid GtkSatModule, since it makes
 * no sense whatsoever to have this kind of popup menu without a GtkSatModule
 * parent.
 *
 */
void gtk_sat_module_popup (GtkSatModule *module)
{
    GtkWidget *menu;        /* The pop-up menu */
    GtkWidget *satsubmenu;  /* Satellite selection submenu */
    GtkWidget *menuitem;    /* Widget used to create the menu items */
    GtkWidget *image;       /* Widget used to create menu item icons */
    
    /* misc variables */
    GList  *sats;
    sat_t  *sat;
    gchar  *buff;
    guint   i,n;



    if ((module == NULL) || !IS_GTK_SAT_MODULE (module)) {
        sat_log_log (SAT_LOG_LEVEL_ERROR,
                     _("%s:%d: %s called with NULL parameter!"),
                     __FILE__, __LINE__, __FUNCTION__);

        return;
    }

    menu = gtk_menu_new ();

    if (module->state == GTK_SAT_MOD_STATE_DOCKED) {

        menuitem = gtk_image_menu_item_new_with_label (_("Detach module"));
        buff = icon_file_name ("gpredict-notebook.png");
        image = gtk_image_new_from_file (buff);
        g_free (buff);
        gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image);
        gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);
        g_signal_connect (menuitem, "activate",
                          G_CALLBACK (docking_state_cb), module);
    }
    else {

        menuitem = gtk_image_menu_item_new_with_label (_("Attach module"));
        buff = icon_file_name ("gpredict-notebook.png");
        image = gtk_image_new_from_file (buff);
        g_free (buff);
        gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image);
        gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);
        g_signal_connect (menuitem, "activate",
                          G_CALLBACK (docking_state_cb), module);

    }

    if (module->state == GTK_SAT_MOD_STATE_FULLSCREEN) {

        menuitem = gtk_image_menu_item_new_with_label (_("Exit full screen"));
        image = gtk_image_new_from_stock (GTK_STOCK_LEAVE_FULLSCREEN,
                                          GTK_ICON_SIZE_MENU);
        gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image);
        gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);
        g_signal_connect (menuitem, "activate",
                          G_CALLBACK (screen_state_cb), module);
    }
    else {
        menuitem = gtk_image_menu_item_new_with_label (_("Full screen"));
        image = gtk_image_new_from_stock (GTK_STOCK_FULLSCREEN,
                                          GTK_ICON_SIZE_MENU);
        gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image);
        gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);
        g_signal_connect (menuitem, "activate",
                          G_CALLBACK (screen_state_cb), module);
    }

    /* separator */
    menuitem = gtk_separator_menu_item_new ();
    gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);

    /* select satellite submenu */
    menuitem = gtk_menu_item_new_with_label(_("Select satellite"));
    gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
    
    satsubmenu = gtk_menu_new();
    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), satsubmenu);
    
    sats = g_hash_table_get_values(module->satellites);  
    sats = g_list_sort(sats , (GCompareFunc) sat_nickname_compare );

    n = g_list_length(sats);
    for (i = 0; i < n; i++) {
        sat = SAT(g_list_nth_data(sats, i));
        menuitem = gtk_menu_item_new_with_label(sat->nickname);
        g_object_set_data(G_OBJECT(menuitem), "catnum", GINT_TO_POINTER(sat->tle.catnr));
        g_signal_connect(menuitem, "activate", G_CALLBACK (sat_selected_cb), module);
        gtk_menu_shell_append(GTK_MENU_SHELL(satsubmenu), menuitem);
    }

    /* separator */
    menuitem = gtk_separator_menu_item_new ();
    gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);

    /* sky at a glance */
    menuitem = gtk_image_menu_item_new_with_label (_("Sky at a glance"));
    buff = icon_file_name ("gpredict-planner-small.png");
    image = gtk_image_new_from_file (buff);
    g_free (buff);
    gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image);
    gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);
    g_signal_connect (menuitem, "activate",
                      G_CALLBACK (sky_at_glance_cb), module);

    /* time manager */
    menuitem = gtk_image_menu_item_new_with_label (_("Time Controller"));
    buff = icon_file_name ("gpredict-clock-small.png");
    image = gtk_image_new_from_file (buff);
    g_free (buff);
    gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image);
    gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);
    g_signal_connect (menuitem, "activate", G_CALLBACK (tmgr_cb), module);
    
    /* separator */
    menuitem = gtk_separator_menu_item_new ();
    gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);

    /* Radio Control */
    menuitem = gtk_image_menu_item_new_with_label (_("Radio Control"));
    buff = icon_file_name ("gpredict-oscilloscope-small.png");
    image = gtk_image_new_from_file (buff);
    g_free (buff);
    gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image);
    gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);
    g_signal_connect (menuitem, "activate", G_CALLBACK (rigctrl_cb), module);
    
    /* Antenna Control */
    menuitem = gtk_image_menu_item_new_with_label (_("Antenna Control"));
    buff = icon_file_name ("gpredict-antenna-small.png");
    image = gtk_image_new_from_file (buff);
    g_free (buff);
    gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image);
    gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);
    g_signal_connect (menuitem, "activate", G_CALLBACK (rotctrl_cb), module);

    /* separator */
    menuitem = gtk_separator_menu_item_new ();
    gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);

    /* configure */
    menuitem = gtk_image_menu_item_new_with_label (_("Configure"));
    image = gtk_image_new_from_stock (GTK_STOCK_PROPERTIES,
                                      GTK_ICON_SIZE_MENU);
    gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image);
    gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);
    g_signal_connect (menuitem, "activate",
                      G_CALLBACK (config_cb), module);

    /* clone */
    menuitem = gtk_image_menu_item_new_with_label (_("Clone..."));
    image = gtk_image_new_from_stock (GTK_STOCK_COPY,
                                      GTK_ICON_SIZE_MENU);
    gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image);
    gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);
    g_signal_connect (menuitem, "activate",
                      G_CALLBACK (clone_cb), module);

    /* separator */
    menuitem = gtk_separator_menu_item_new ();
    gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);

    /* delete module */
    menuitem = gtk_image_menu_item_new_with_label (_("Delete"));
    image = gtk_image_new_from_stock (GTK_STOCK_DELETE,
                                      GTK_ICON_SIZE_MENU);
    gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image);
    gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);
    g_signal_connect (menuitem, "activate",
                      G_CALLBACK (delete_cb), module);

    /* close */
    menuitem = gtk_image_menu_item_new_with_label (_("Close"));
    image = gtk_image_new_from_stock (GTK_STOCK_CLOSE,
                                      GTK_ICON_SIZE_MENU);
    gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image);
    gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);
    g_signal_connect (menuitem, "activate",
                      G_CALLBACK (close_cb), module);

    gtk_widget_show_all (menu);

    gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
                    0, gdk_event_get_time (NULL));
}
/** \brief Toggle dockig state.
 *
 * This function is called when the user selects the (Un)Dock menu
 * item in the GtkSatModule popup menu. If the current module state
 * is DOCKED, the module will be undocked and moved into it's own,
 * GtkWindow. If the current module state is WINDOW or FULLSCREEN,
 * the module will be docked.
 *
 * The text of the menu item will be changed corresponding to the
 * action that has been performed.
 */
static void docking_state_cb (GtkWidget *menuitem, gpointer data)
{
    GtkWidget *module = GTK_WIDGET (data);
    GtkAllocation aloc;
    gint       w,h;
    gchar     *icon;      /* icon file name */
    gchar     *title;     /* window title */

    (void) menuitem; /* avoid unused parameter compiler warning */

    gtk_widget_get_allocation ( module, &aloc);
    
    switch (GTK_SAT_MODULE (module)->state) {

    case GTK_SAT_MOD_STATE_DOCKED:

        /* get stored size; use size from main window if size not explicitly stoed */
        if (g_key_file_has_key (GTK_SAT_MODULE (module)->cfgdata,
                                MOD_CFG_GLOBAL_SECTION,
                                MOD_CFG_WIN_WIDTH,
                                NULL)) {
            w = g_key_file_get_integer (GTK_SAT_MODULE (module)->cfgdata,
                                        MOD_CFG_GLOBAL_SECTION,
                                        MOD_CFG_WIN_WIDTH,
                                        NULL);
        }
        else {
            w = aloc.width;
        }
        if (g_key_file_has_key (GTK_SAT_MODULE (module)->cfgdata,
                                MOD_CFG_GLOBAL_SECTION,
                                MOD_CFG_WIN_HEIGHT,
                                NULL)) {
            h = g_key_file_get_integer (GTK_SAT_MODULE (module)->cfgdata,
                                        MOD_CFG_GLOBAL_SECTION,
                                        MOD_CFG_WIN_HEIGHT,
                                        NULL);
        }
        else {
            h = aloc.height;
        }
        
        /* increase reference count of module */
        g_object_ref (module);

        /* we don't need the positions */
        //GTK_SAT_MODULE (module)->vpanedpos = -1;
        //GTK_SAT_MODULE (module)->hpanedpos = -1;

        /* undock from mod-mgr */
        mod_mgr_undock_module (module);

        /* create window */
        GTK_SAT_MODULE (module)->win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
        title = g_strconcat (_("GPREDICT: "),
                             GTK_SAT_MODULE (module)->name,
                             " (", GTK_SAT_MODULE (module)->qth->name, ")",
                             NULL);
        gtk_window_set_title (GTK_WINDOW (GTK_SAT_MODULE (module)->win), title);
        g_free (title);
        gtk_window_set_default_size (GTK_WINDOW (GTK_SAT_MODULE (module)->win), w, h);
        g_signal_connect (G_OBJECT (GTK_SAT_MODULE (module)->win), "configure_event",
                          G_CALLBACK (module_window_config_cb), module);

        /* window icon */
        icon = icon_file_name ("gpredict-icon.png");
        if (g_file_test (icon, G_FILE_TEST_EXISTS)) {
            gtk_window_set_icon_from_file (GTK_WINDOW (GTK_SAT_MODULE (module)->win), icon, NULL);
        }
        g_free (icon);

        /* move window to stored position if requested by configuration */
        if (sat_cfg_get_bool (SAT_CFG_BOOL_MOD_WIN_POS) &&
            g_key_file_has_key (GTK_SAT_MODULE (module)->cfgdata,
                                MOD_CFG_GLOBAL_SECTION,
                                MOD_CFG_WIN_POS_X,
                                NULL) &&
            g_key_file_has_key (GTK_SAT_MODULE (module)->cfgdata,
                                MOD_CFG_GLOBAL_SECTION,
                                MOD_CFG_WIN_POS_Y,
                                NULL)) {

            gtk_window_move (GTK_WINDOW (GTK_SAT_MODULE (module)->win),
                             g_key_file_get_integer (GTK_SAT_MODULE (module)->cfgdata,
                                                     MOD_CFG_GLOBAL_SECTION,
                                                     MOD_CFG_WIN_POS_X, NULL),
                             g_key_file_get_integer (GTK_SAT_MODULE (module)->cfgdata,
                                                     MOD_CFG_GLOBAL_SECTION,
                                                     MOD_CFG_WIN_POS_Y,
                                                     NULL));

        }

        /* add module to window */
        gtk_container_add (GTK_CONTAINER (GTK_SAT_MODULE (module)->win), module);

        /* change internal state */
        GTK_SAT_MODULE (module)->state = GTK_SAT_MOD_STATE_WINDOW;

        /* store new state in configuration */
        g_key_file_set_integer (GTK_SAT_MODULE (module)->cfgdata,
                                MOD_CFG_GLOBAL_SECTION,
                                MOD_CFG_STATE,
                                GTK_SAT_MOD_STATE_WINDOW);

        /* decrease reference count of module */
        g_object_unref (module);

        /* show window */
        gtk_widget_show_all (GTK_SAT_MODULE (module)->win);
        
        /* reparent time manager window if visible */
        if (GTK_SAT_MODULE (module)->tmgActive) {
            gtk_window_set_transient_for (GTK_WINDOW (GTK_SAT_MODULE (module)->tmgWin),
                                          GTK_WINDOW (GTK_SAT_MODULE (module)->win));
        }

        break;

     case GTK_SAT_MOD_STATE_WINDOW:
     case GTK_SAT_MOD_STATE_FULLSCREEN:

        /* increase referene count */
        g_object_ref (module);

        /* reparent time manager window if visible */
        if (GTK_SAT_MODULE (module)->tmgActive) {
            gtk_window_set_transient_for (GTK_WINDOW (GTK_SAT_MODULE (module)->tmgWin),
                                          GTK_WINDOW (app));
        }

        /* remove module from window, destroy window */
        gtk_container_remove (GTK_CONTAINER (GTK_SAT_MODULE (module)->win), module);
        gtk_widget_destroy (GTK_SAT_MODULE (module)->win);
        GTK_SAT_MODULE (module)->win = NULL;

        /* dock into mod-mgr */
        mod_mgr_dock_module (module);

        /* change internal state */
        GTK_SAT_MODULE (module)->state = GTK_SAT_MOD_STATE_DOCKED;
        
        /* store new state in configuration */
        g_key_file_set_integer (GTK_SAT_MODULE (module)->cfgdata,
                                MOD_CFG_GLOBAL_SECTION,
                                MOD_CFG_STATE,
                                GTK_SAT_MOD_STATE_DOCKED);

        /* decrease reference count of module */
        g_object_unref (module);


        break;

     default:

        sat_log_log (SAT_LOG_LEVEL_ERROR,
                     _("%s:%d: Unknown module state: %d"),
                     __FILE__, __LINE__, GTK_SAT_MODULE (module)->state);
        break;

    }


}
/** \brief Toggle screen state.
 *
 * This function is intended to toggle between FULLSCREEN
 * and WINDOW state.
 */
static void screen_state_cb  (GtkWidget *menuitem, gpointer data)
{
    GtkWidget *module = GTK_WIDGET (data);
    gint       w,h;
    gchar     *icon;      /* icon file name */
    gchar     *title;     /* window title */

    (void) menuitem; /* avoid unused parameter compiler warning */

    switch (GTK_SAT_MODULE (module)->state) {

    case GTK_SAT_MOD_STATE_DOCKED:

        /* increase reference count of module */
        g_object_ref (module);

        /* undock from mod-mgr */
        mod_mgr_undock_module (module);

        /* create window */
        GTK_SAT_MODULE (module)->win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
        title = g_strconcat (_("GPREDICT: "),
                             GTK_SAT_MODULE (module)->name,
                             " (", GTK_SAT_MODULE (module)->qth->name, ")",
                             NULL);
        gtk_window_set_title (GTK_WINDOW (GTK_SAT_MODULE (module)->win), title);
        g_free (title);

        /* window icon */
        icon = icon_file_name ("gpredict-icon.png");
        if (g_file_test (icon, G_FILE_TEST_EXISTS)) {
            gtk_window_set_icon_from_file (GTK_WINDOW (GTK_SAT_MODULE (module)->win), icon, NULL);
        }
        g_free (icon);

        /* add module to window */
        gtk_container_add (GTK_CONTAINER (GTK_SAT_MODULE (module)->win), module);

        /* change internal state */
        GTK_SAT_MODULE (module)->state = GTK_SAT_MOD_STATE_FULLSCREEN;

        /* decrease reference count of module */
        g_object_unref (module);

        gtk_window_fullscreen (GTK_WINDOW (GTK_SAT_MODULE (module)->win));

        /* show window */
        gtk_widget_show_all (GTK_SAT_MODULE (module)->win);
        
        /* reparent time manager window if visible */
        if (GTK_SAT_MODULE (module)->tmgActive) {
            gtk_window_set_transient_for (GTK_WINDOW (GTK_SAT_MODULE (module)->tmgWin),
                                          GTK_WINDOW (GTK_SAT_MODULE (module)->win));
        }

        break;


     case GTK_SAT_MOD_STATE_WINDOW:
        /* change internal state */
        GTK_SAT_MODULE (module)->state = GTK_SAT_MOD_STATE_FULLSCREEN;
        gtk_window_fullscreen (GTK_WINDOW (GTK_SAT_MODULE (module)->win));
        gtk_window_set_default_size (GTK_WINDOW (GTK_SAT_MODULE (module)->win), 800, 600);

        break;


     case GTK_SAT_MOD_STATE_FULLSCREEN:
        /* change internal state */
        GTK_SAT_MODULE (module)->state = GTK_SAT_MOD_STATE_WINDOW;
        gtk_window_unfullscreen (GTK_WINDOW (GTK_SAT_MODULE (module)->win));

        /* get stored size; use some standard size if not explicitly specified */
        if (g_key_file_has_key (GTK_SAT_MODULE (module)->cfgdata, MOD_CFG_GLOBAL_SECTION, MOD_CFG_WIN_WIDTH, NULL)) {
            w = g_key_file_get_integer (GTK_SAT_MODULE (module)->cfgdata, MOD_CFG_GLOBAL_SECTION, MOD_CFG_WIN_WIDTH, NULL);
        }
        else {
            w = 800;
        }
        if (g_key_file_has_key (GTK_SAT_MODULE (module)->cfgdata, MOD_CFG_GLOBAL_SECTION, MOD_CFG_WIN_HEIGHT, NULL)) {
            h = g_key_file_get_integer (GTK_SAT_MODULE (module)->cfgdata, MOD_CFG_GLOBAL_SECTION, MOD_CFG_WIN_HEIGHT, NULL);
        }
        else {
            h = 600;
        }
        gtk_window_set_default_size (GTK_WINDOW (GTK_SAT_MODULE (module)->win), w, h);

        /* move window to stored position if requested by configuration */
        if (sat_cfg_get_bool (SAT_CFG_BOOL_MOD_WIN_POS) &&
            g_key_file_has_key (GTK_SAT_MODULE (module)->cfgdata, MOD_CFG_GLOBAL_SECTION, MOD_CFG_WIN_POS_X, NULL) &&
            g_key_file_has_key (GTK_SAT_MODULE (module)->cfgdata, MOD_CFG_GLOBAL_SECTION, MOD_CFG_WIN_POS_Y, NULL)) {

            gtk_window_move (GTK_WINDOW (GTK_SAT_MODULE (module)->win),
                             g_key_file_get_integer (GTK_SAT_MODULE (module)->cfgdata, MOD_CFG_GLOBAL_SECTION, MOD_CFG_WIN_POS_X, NULL),
                             g_key_file_get_integer (GTK_SAT_MODULE (module)->cfgdata, MOD_CFG_GLOBAL_SECTION, MOD_CFG_WIN_POS_Y, NULL));

        }

        /* store new state in configuration */
        g_key_file_set_integer (GTK_SAT_MODULE (module)->cfgdata, MOD_CFG_GLOBAL_SECTION, MOD_CFG_STATE, GTK_SAT_MOD_STATE_WINDOW);

        break;

     default:

        sat_log_log (SAT_LOG_LEVEL_ERROR,
                     _("%s:%d: Unknown module state: %d"),
                     __FILE__, __LINE__, GTK_SAT_MODULE (module)->state);
        break;

    }

}
/** \brief Clone module.
 *
 * This function is called when the user selects the clone
 * menu item in the GtkSatModule popup menu. the function creates
 * a dialog in which the user is asked for a new module name.
 * When a valid module name is available and the user clicks on OK,
 * an exact copy of the currwent module is created.
 * By default, the nes module will be opened but the user has the
 * possibility to override this in the dialog window.
 *
 */
static void clone_cb (GtkWidget *menuitem, gpointer data)
{
    GtkWidget    *dialog;
    GtkWidget    *entry;
    GtkWidget    *label;
    GtkWidget    *toggle;
    GtkWidget    *vbox;
    GtkAllocation aloc;
    guint         response;
    GtkSatModule *module = GTK_SAT_MODULE (data);
    GtkSatModule *newmod;
    gchar        *source,*target;
    gchar        *icon;      /* icon file name */
    gchar        *title;     /* window title */

    (void) menuitem; /* avoid unused parameter compiler warning */

    dialog = gtk_dialog_new_with_buttons (_("Clone Module"),
                                          GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (module))),
                                          GTK_DIALOG_MODAL |
                                          GTK_DIALOG_DESTROY_WITH_PARENT,
                                          GTK_STOCK_CANCEL,
                                          GTK_RESPONSE_CANCEL,
                                          GTK_STOCK_OK,
                                          GTK_RESPONSE_OK,
                                          NULL);
    gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);

    /* label */
    label = gtk_label_new (_("Name of new module:"));
    vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
    gtk_box_pack_start (GTK_BOX(vbox), label, FALSE, FALSE, 0);

    /* name entry */
    entry = gtk_entry_new ();
    gtk_entry_set_max_length (GTK_ENTRY (entry), 25);
    gtk_entry_set_text (GTK_ENTRY (entry), module->name);
    gtk_widget_set_tooltip_text (entry,
                          _("Enter a short name for this module.\n"\
                            "Allowed characters: 0..9, a..z, A..Z, - and _"));
        
    /*not sure what to do with the old private tip the new api does not like them
      _("The name will be used to identify the module "                 \
                            "and it is also used a file name for saving the data."\
                            "Max length is 25 characters."));
    */
    /* attach changed signal so that we can enable OK button when
        a proper name has been entered
        oh, btw. disable OK button to begin with....
     */
    gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
                                       GTK_RESPONSE_OK,
                                       FALSE);
    g_signal_connect (entry, "changed", G_CALLBACK (name_changed), dialog);
    gtk_box_pack_start (GTK_BOX( vbox ), entry, FALSE, FALSE, 0);


    /* check button */
    toggle = gtk_check_button_new_with_label (_("Open module when created"));
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), TRUE);
    gtk_widget_set_tooltip_text ( toggle,                          
                          _("If checked, the new module will be opened "\
                            "after it has been created"));
    gtk_box_pack_start (GTK_BOX (vbox),
                        toggle, FALSE, FALSE, 20);


    gtk_widget_show_all (vbox);

    /* run dialog */
    response = gtk_dialog_run (GTK_DIALOG (dialog));

    switch (response) {

    case GTK_RESPONSE_OK:
        sat_log_log (SAT_LOG_LEVEL_INFO,
                     _("%s:%d: Cloning %s => %s"),
                     __FILE__, __LINE__, module->name,
                     gtk_entry_get_text (GTK_ENTRY (entry)));

        /* build full file names */
        gchar *moddir = get_modules_dir ();
        source = g_strconcat (moddir, G_DIR_SEPARATOR_S,
                              module->name, ".mod", NULL);
        target = g_strconcat (moddir, G_DIR_SEPARATOR_S,
                              gtk_entry_get_text (GTK_ENTRY (entry)), ".mod", NULL);
        g_free (moddir);

        /* copy file */
        if (gpredict_file_copy (source, target)) {
            sat_log_log (SAT_LOG_LEVEL_ERROR,
                         _("%s:%d: Failed to clone %s."),
                         __FILE__, __LINE__, module->name);
        }
        else {
            sat_log_log (SAT_LOG_LEVEL_INFO,
                         _("%s:%d: Successfully cloned %s."),
                         __FILE__, __LINE__, module->name);

            /* open module if requested */
            if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (toggle))) {

                newmod = GTK_SAT_MODULE (gtk_sat_module_new (target));
                newmod->state = module->state;

                if (newmod->state == GTK_SAT_MOD_STATE_DOCKED) {

                    /* add to module manager */
                    mod_mgr_add_module (GTK_WIDGET (newmod), TRUE);

                }
                else {
                    /* add to module manager */
                    mod_mgr_add_module (GTK_WIDGET (newmod), FALSE);

                    /* create window */
                    newmod->win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
                    gtk_window_set_title (GTK_WINDOW (newmod->win),
                                          newmod->name);
                    title = g_strconcat (_("GPREDICT: "),
                                         newmod->name,
                                         " (", newmod->qth->name, ")",
                                         NULL);
                    gtk_window_set_title (GTK_WINDOW (newmod->win), title);
                    g_free (title);

                    /* use size of source module */
                    gtk_widget_get_allocation(GTK_WIDGET (module), &aloc);
                    gtk_window_set_default_size (GTK_WINDOW (newmod->win),
                                                 aloc.width,
                                                 aloc.height);

                    g_signal_connect (G_OBJECT (newmod->win), "configure_event",
                                      G_CALLBACK (module_window_config_cb), newmod);

                    /* add module to window */
                    gtk_container_add (GTK_CONTAINER (newmod->win),
                                       GTK_WIDGET (newmod));

                    /* window icon */
                    icon = icon_file_name ("gpredict-icon.png");
                    if (g_file_test (icon, G_FILE_TEST_EXISTS)) {
                        gtk_window_set_icon_from_file (GTK_WINDOW (newmod->win), icon, NULL);
                    }
                    g_free (icon);

                    /* show window */
                    gtk_widget_show_all (newmod->win);

                }
            }
        }

        /* clean up */
        g_free (source);
        g_free (target);

        break;

     case GTK_RESPONSE_CANCEL:
        sat_log_log (SAT_LOG_LEVEL_INFO,
                     _("%s:%d: Cloning cancelled by user."),
                     __FILE__, __LINE__);
        break;

     default:
        sat_log_log (SAT_LOG_LEVEL_INFO,
                     _("%s:%d: Cloning interrupted."),
                     __FILE__, __LINE__);
        break;
    }

    gtk_widget_destroy (dialog);

}
/** \brief Show a text file in the gpredict system directory
 *  \param filename The basic file name
 *
 * This function is intended to display files like NEWS, COPYING, etc.
 * Note that on windows these files have .txt suffix, while on Unix they
 * do not.
 *
 */
void
gpredict_help_show_txt (const gchar *filename)
{
     GtkWidget     *dialog;
     GtkWidget     *swin;
     GtkWidget     *view;
     GtkTextBuffer *txtbuf;
     GIOChannel    *chan;
     GError        *error = NULL;
     gchar         *fname;
     gchar         *buff;
     gsize          length;


     /* get system data directory */
#ifdef G_OS_UNIX
     fname = g_strconcat (PACKAGE_DATA_DIR, G_DIR_SEPARATOR_S, filename, NULL);
#else
#  ifdef G_OS_WIN32
        buff = g_win32_get_package_installation_directory (NULL, NULL);
        fname = g_strconcat (buff, G_DIR_SEPARATOR_S,
                                    "doc", G_DIR_SEPARATOR_S,
                                    filename, ".txt", NULL);
        g_free (buff);
#  endif
#endif

     /* load file into buffer */
     chan = g_io_channel_new_file (fname, "r", &error);
     if (error != NULL) {
          sat_log_log (SAT_LOG_LEVEL_ERROR,
                          _("%s: Failed to load %s (%s)"),
                          __FUNCTION__, fname, error->message);
          g_free (fname);
          g_clear_error (&error);

          return;
     }

     g_io_channel_read_to_end (chan, &buff, &length, &error);
     if (error != NULL) {
          sat_log_log (SAT_LOG_LEVEL_ERROR,
                          _("%s: Error reading %s (%s)"),
                          __FUNCTION__, fname, error->message);

          g_free (buff);
          g_clear_error (&error);
          g_io_channel_shutdown (chan, TRUE, NULL);
          g_io_channel_unref (chan);

          return;
     }

     g_free (fname);
          
     /* create text view and text buffer widgets */
     view = gtk_text_view_new ();
     gtk_text_view_set_editable (GTK_TEXT_VIEW (view), FALSE);
     gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view), FALSE);
     txtbuf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));

     gtk_text_buffer_set_text (txtbuf, buff, -1);
     g_free (buff);

     /* scrolled window */
     swin = gtk_scrolled_window_new (NULL, NULL);
     gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swin),
                                                   GTK_SHADOW_ETCHED_IN);
     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
                                             GTK_POLICY_NEVER,
                                             GTK_POLICY_AUTOMATIC);
     gtk_container_add (GTK_CONTAINER (swin), view);

     /* create and show dialogue with textbuffer */
     dialog = gtk_dialog_new_with_buttons (_("Gpredict Info"),
                                                    NULL,
                                                    0,
                                                    GTK_STOCK_CLOSE,
                                                    GTK_RESPONSE_ACCEPT,
                                                    NULL);
     gtk_widget_set_size_request (dialog, -1, 450);
     buff = icon_file_name ("gpredict-icon.png");
     gtk_window_set_icon_from_file (GTK_WINDOW (dialog), buff, NULL);
     g_free (buff);

     g_signal_connect_swapped (dialog, "response", 
                                     G_CALLBACK (gtk_widget_destroy), dialog);

     gtk_container_add (GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), swin);
     gtk_widget_show_all (dialog);

}
Exemple #12
0
/**
 * Create and run preferences dialog.
 *
 * The preferences dialog contains a GtkNoteBook, which is used to group
 * the various configuration parts/modules (General, Modules, Interfaces, ...).
 * Each configuration part can contain several subgroups that are managed
 * by the module itself. As an example, consider the "Modules" tab which
 * could have the following sub-groups: General, List View, Map View and so on.
 * The tabs of the notebook are invisible, instead a vertical icon list
 * placed on the left of the notebook is used to navigate through the
 * notebook pages. The icon list is actually impemented using pixmap buttons
 * in a button box. Using something like the GtkIconView would have been better
 * but that seems to be rather useless when packed into a box.
 */
void sat_pref_run()
{
    GtkWidget      *nbook;      /* notebook widget */
    GtkWidget      *hbox;       /* horizontal box */
    GtkWidget      *butbox;
    GtkWidget      *genbut, *modbut, *ifbut, *predbut;
    gchar          *iconfile;
    gint            response;

    /* Create notebook and add individual pages.
       The individual pages will need the GKeyFile
     */
    nbook = gtk_notebook_new();
    gtk_notebook_append_page(GTK_NOTEBOOK(nbook),
                             sat_pref_general_create(),
                             gtk_label_new(_("General")));
    gtk_notebook_append_page(GTK_NOTEBOOK(nbook),
                             sat_pref_modules_create(NULL),
                             gtk_label_new(_("Modules")));
    gtk_notebook_append_page(GTK_NOTEBOOK(nbook),
                             sat_pref_interfaces_create(),
                             gtk_label_new(_("Interfaces")));
    gtk_notebook_append_page(GTK_NOTEBOOK(nbook),
                             sat_pref_predict_create(),
                             gtk_label_new(_("Predict")));

    gtk_notebook_set_show_tabs(GTK_NOTEBOOK(nbook), FALSE);
    gtk_notebook_set_show_border(GTK_NOTEBOOK(nbook), FALSE);

    /* create a button box and add the buttons one by one */
    genbut = gpredict_vpixmap_button("gpredict-sat-pref.png",
                                     _("General"), NULL);
    gtk_button_set_relief(GTK_BUTTON(genbut), GTK_RELIEF_NONE);
    g_object_set_data(G_OBJECT(genbut), "page",
                      GINT_TO_POINTER(NBOOK_PAGE_GENERAL));
    g_signal_connect(G_OBJECT(genbut), "clicked",
                     G_CALLBACK(button_press_cb), nbook);

    modbut = gpredict_vpixmap_button("gpredict-sat-list.png",
                                     _("Modules"), NULL);
    gtk_button_set_relief(GTK_BUTTON(modbut), GTK_RELIEF_NONE);
    g_object_set_data(G_OBJECT(modbut), "page",
                      GINT_TO_POINTER(NBOOK_PAGE_MODULES));
    g_signal_connect(G_OBJECT(modbut), "clicked",
                     G_CALLBACK(button_press_cb), nbook);

    ifbut = gpredict_vpixmap_button("gpredict-oscilloscope.png",
                                    _("Interfaces"), NULL);
    gtk_button_set_relief(GTK_BUTTON(ifbut), GTK_RELIEF_NONE);
    g_object_set_data(G_OBJECT(ifbut), "page",
                      GINT_TO_POINTER(NBOOK_PAGE_INTERFACE));
    g_signal_connect(G_OBJECT(ifbut), "clicked",
                     G_CALLBACK(button_press_cb), nbook);

    predbut = gpredict_vpixmap_button("gpredict-calendar.png",
                                      _("Predict"), NULL);
    gtk_button_set_relief(GTK_BUTTON(predbut), GTK_RELIEF_NONE);
    g_object_set_data(G_OBJECT(predbut), "page",
                      GINT_TO_POINTER(NBOOK_PAGE_PREDICT));
    g_signal_connect(G_OBJECT(predbut), "clicked",
                     G_CALLBACK(button_press_cb), nbook);

    butbox = gtk_vbutton_box_new();
    gtk_button_box_set_layout(GTK_BUTTON_BOX(butbox), GTK_BUTTONBOX_START);
    gtk_container_add(GTK_CONTAINER(butbox), genbut);
    gtk_container_add(GTK_CONTAINER(butbox), modbut);
    gtk_container_add(GTK_CONTAINER(butbox), ifbut);
    gtk_container_add(GTK_CONTAINER(butbox), predbut);

    /* create horizontal box which will contain the icon list on the left side
       and the notebook on the right side.
     */
    hbox = gtk_hbox_new(FALSE, 5);
    gtk_box_pack_start(GTK_BOX(hbox), butbox, FALSE, FALSE, 0);
    gtk_box_pack_start(GTK_BOX(hbox), nbook, TRUE, TRUE, 0);
    gtk_widget_show_all(hbox);

    /* create and display preferences window */
    window = gtk_dialog_new_with_buttons(_("Gpredict Preferences :: General"),
                                         GTK_WINDOW(app),
                                         GTK_DIALOG_MODAL |
                                         GTK_DIALOG_DESTROY_WITH_PARENT,
                                         GTK_STOCK_CANCEL,
                                         GTK_RESPONSE_REJECT,
                                         GTK_STOCK_OK,
                                         GTK_RESPONSE_ACCEPT, NULL);
    iconfile = icon_file_name("gpredict-sat-pref.png");
    gtk_window_set_icon_from_file(GTK_WINDOW(window), iconfile, NULL);
    g_free(iconfile);

    gtk_box_pack_start(GTK_BOX
                       (gtk_dialog_get_content_area(GTK_DIALOG(window))),
                       hbox, TRUE, TRUE, 0);
    gtk_box_set_spacing(GTK_BOX
                        (gtk_dialog_get_content_area(GTK_DIALOG(window))), 10);

    gtk_button_clicked(GTK_BUTTON(genbut));

    response = gtk_dialog_run(GTK_DIALOG(window));
    switch (response)
    {
    case GTK_RESPONSE_ACCEPT:
        sat_pref_general_ok();
        sat_pref_modules_ok(NULL);
        sat_pref_interfaces_ok();
        sat_pref_predict_ok();
        sat_cfg_save();
        break;

    default:
        sat_pref_general_cancel();
        sat_pref_modules_cancel(NULL);
        sat_pref_interfaces_cancel();
        sat_pref_predict_cancel();
        break;
    }
    gtk_widget_destroy(window);
}
/** \brief Show details about a satellite pass.
 *  \param satname The name of the satellite.
 *  \param qth Pointer to the QTH data.
 *  \param passes List of passes to show.
 *  \param toplevel The toplevel window or NULL.
 *
 * This function creates a dialog window with a list showing the
 * details of a pass.
 *
 */
void show_passes (const gchar *satname, qth_t *qth, GSList *passes, GtkWidget *toplevel)
{
    GtkWidget         *dialog;
    GtkWidget         *list;
    GtkListStore      *liststore;
    GtkCellRenderer   *renderer;
    GtkTreeViewColumn *column;
    GtkTreeIter        item;
    GtkWidget         *swin;
    gchar             *title;
    guint              flags;
    guint              i, num;
    pass_t            *pass = NULL; 
    gchar             *buff;



    /* get columns flags */
    flags = sat_cfg_get_int (SAT_CFG_INT_PRED_MULTI_COL);

    /* create list */
    list = gtk_tree_view_new ();
    gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (list), TRUE);

    for (i = 0; i < MULTI_PASS_COL_NUMBER; i++) {

        renderer = gtk_cell_renderer_text_new ();
        g_object_set (G_OBJECT (renderer), "xalign", MULTI_PASS_COL_XALIGN[i], NULL);
        column = gtk_tree_view_column_new_with_attributes (_(MULTI_PASS_COL_TITLE[i]),
                                                           renderer,
                                                           "text", i,
                                                           NULL);
        gtk_tree_view_insert_column (GTK_TREE_VIEW (list), column, -1);

        /* only aligns the headers */
        gtk_tree_view_column_set_alignment (column, 0.5);

        /* set cell data function; allows to format data before rendering */
        check_and_set_multi_cell_renderer (column, renderer, i);

        /* hide columns that have not been specified */
        if (!(flags & (1 << i))) {
            gtk_tree_view_column_set_visible (column, FALSE);
        }


    }

    /* create and fill model */
    liststore = gtk_list_store_new (MULTI_PASS_COL_NUMBER+1,
                                    G_TYPE_DOUBLE,   // aos time
                                    G_TYPE_DOUBLE,   // tca time
                                    G_TYPE_DOUBLE,   // los time
                                    G_TYPE_DOUBLE,   // duration
                                    G_TYPE_DOUBLE,   // aos az
                                    G_TYPE_DOUBLE,   // max el
                                    G_TYPE_DOUBLE,   // az @ max el
                                    G_TYPE_DOUBLE,   // los az
                                    G_TYPE_INT,      // orbit
                                    G_TYPE_STRING,   // visibility
                                    G_TYPE_INT);     // row number

    /* add rows to list store */
    num = g_slist_length (passes);
    
    for (i = 0; i < num; i++) {

        pass = PASS(g_slist_nth_data (passes, i));

        gtk_list_store_append (liststore, &item);
        gtk_list_store_set (liststore, &item,
                            MULTI_PASS_COL_AOS_TIME, pass->aos,
                            MULTI_PASS_COL_TCA, pass->tca,
                            MULTI_PASS_COL_LOS_TIME, pass->los,
                            MULTI_PASS_COL_DURATION, (pass->los - pass->aos),
                            MULTI_PASS_COL_AOS_AZ, pass->aos_az,
                            MULTI_PASS_COL_MAX_EL, pass->max_el,
                            MULTI_PASS_COL_MAX_EL_AZ, pass->maxel_az,
                            MULTI_PASS_COL_LOS_AZ, pass->los_az,
                            MULTI_PASS_COL_ORBIT, pass->orbit,
                            MULTI_PASS_COL_VIS, pass->vis,
                            MULTI_PASS_COL_NUMBER, i,
                            -1);


    }

    /* connect model to tree view */
    gtk_tree_view_set_model (GTK_TREE_VIEW (list), GTK_TREE_MODEL (liststore));
    g_object_unref (liststore);

    /* store reference to passes and QTH */
    g_object_set_data (G_OBJECT (list), "passes", passes);
    g_object_set_data (G_OBJECT (list), "qth", qth);

    /* mouse events => popup menu */
    g_signal_connect (list, "button-press-event",
                      G_CALLBACK (button_press_cb), NULL);
    g_signal_connect (list, "popup-menu",
                      G_CALLBACK (popup_menu_cb), NULL);


    /* "row-activated" signal is used to catch double click events, which means
       a pass has been double clicked => show details */
    g_signal_connect (list, "row-activated",
                      G_CALLBACK(row_activated_cb), toplevel);


    /* scrolled window */
    swin = gtk_scrolled_window_new (NULL, NULL);
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
                                    GTK_POLICY_NEVER,
                                    GTK_POLICY_AUTOMATIC);

    gtk_container_add (GTK_CONTAINER (swin), list);


    /* create dialog */
    title = g_strdup_printf (_("Upcoming passes for %s"), satname);

    /* use NULL as parent to avoid conflict when using undocked windows
       as parents.    */
    dialog = gtk_dialog_new_with_buttons (title,
                                          GTK_WINDOW (toplevel),
                                          GTK_DIALOG_DESTROY_WITH_PARENT,
                                          GTK_STOCK_PRINT, RESPONSE_PRINT,
                                          GTK_STOCK_SAVE, RESPONSE_SAVE,
                                          GTK_STOCK_CLOSE,
                                          GTK_RESPONSE_CLOSE,
                                          NULL);
    g_free (title);

    /* Make Close button default */
    gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);

    /* window icon */
    buff = icon_file_name ("gpredict-sat-list.png");
    gtk_window_set_icon_from_file (GTK_WINDOW (dialog), buff, NULL);
    g_free (buff);

    /* allow interaction with other windows */
    gtk_window_set_modal (GTK_WINDOW (dialog), FALSE);

    g_object_set_data (G_OBJECT (dialog), "sat", (gpointer) satname);
    g_object_set_data (G_OBJECT (dialog), "qth", qth);
    g_object_set_data (G_OBJECT (dialog), "passes", passes);

    g_signal_connect (dialog, "response",
                      G_CALLBACK (multi_pass_response), NULL);
    g_signal_connect (dialog, "destroy",
                      G_CALLBACK (multi_pass_dialog_destroy), NULL);
    g_signal_connect (dialog, "delete_event",
                      G_CALLBACK (multi_pass_dialog_delete), NULL);


    gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area(GTK_DIALOG (dialog))), swin);

    gtk_window_set_default_size (GTK_WINDOW (dialog), -1, 300);
    gtk_widget_show_all (dialog);


}
/** \brief Show details about a satellite pass.
 *  \param parent The parent widget.
 *  \param satname The name of the satellite.
 *  \param qth Pointer to the QTH data.
 *  \param pass The pass info.
 *  \param toplevel The toplevel window or NULL.
 *
 * This function creates a dialog window containing a notebook with three pages:
 *   1. A list showing the details of a pass
 *   2. Polar plot of the pass
 *   3. Az/El plot of the pass
 *
 * Reference to the parent widget is needed to acquire the correct top-level
 * window, otherwise simply using the main window would bring that to front
 * covering any possible module windows. This would be unfortunate in the case
 * of fullscreen modules.
 *
 */
void show_pass (const gchar *satname, qth_t *qth, pass_t *pass, GtkWidget *toplevel)
{
    GtkWidget         *dialog;      /* the dialogue window */
    GtkWidget         *notebook;    /* the notebook widet */
    GtkWidget         *list;
    GtkListStore      *liststore;
    GtkCellRenderer   *renderer;
    GtkTreeViewColumn *column;
    GtkTreeIter        item;
    GtkWidget         *swin;        /* scrolled window containing the list view */
    GtkWidget         *polar;       /* polar plot */
    GtkWidget         *azel;        /* Az/El plot */
    GtkWidget         *hbox;        /* hbox used in tab headers */
    GtkWidget         *image;       /* icon used in tab header */
    gchar             *title;
    guint              flags;
    guint              i, num;
    pass_detail_t     *detail;
    gchar             *buff;
    gint               retcode;
    gdouble            doppler;
    gdouble            delay;
    gdouble            loss;
    obs_astro_t        astro;
    gdouble            ra,dec;


    /* get columns flags */
    flags = sat_cfg_get_int (SAT_CFG_INT_PRED_SINGLE_COL);

    /* create list */
    list = gtk_tree_view_new ();
    gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (list), TRUE);

    for (i = 0; i < SINGLE_PASS_COL_NUMBER; i++) {

        renderer = gtk_cell_renderer_text_new ();
        g_object_set (G_OBJECT (renderer), "xalign", SINGLE_PASS_COL_XALIGN[i], NULL);
        column = gtk_tree_view_column_new_with_attributes (_(SINGLE_PASS_COL_TITLE[i]),
                                                           renderer,
                                                           "text", i,
                                                           NULL);
        gtk_tree_view_insert_column (GTK_TREE_VIEW (list), column, -1);

        /* only aligns the headers */
        gtk_tree_view_column_set_alignment (column, 0.5);

        /* set cell data function; allows to format data before rendering */
        check_and_set_single_cell_renderer (column, renderer, i);

        /* hide columns that have not been specified */
        if (!(flags & (1 << i))) {
            gtk_tree_view_column_set_visible (column, FALSE);
        }


    }

    /* create and fill model */
    liststore = gtk_list_store_new (SINGLE_PASS_COL_NUMBER,
                                    G_TYPE_DOUBLE,   // time
                                    G_TYPE_DOUBLE,   // az
                                    G_TYPE_DOUBLE,   // el
                                    G_TYPE_DOUBLE,   // ra
                                    G_TYPE_DOUBLE,   // dec
                                    G_TYPE_DOUBLE,   // range
                                    G_TYPE_DOUBLE,   // range rate
                                    G_TYPE_DOUBLE,   // lat
                                    G_TYPE_DOUBLE,   // lon
                                    G_TYPE_STRING,   // SSP
                                    G_TYPE_DOUBLE,   // footprint
                                    G_TYPE_DOUBLE,   // alt
                                    G_TYPE_DOUBLE,   // vel
                                    G_TYPE_DOUBLE,   // doppler
                                    G_TYPE_DOUBLE,   // loss
                                    G_TYPE_DOUBLE,   // delay
                                    G_TYPE_DOUBLE,   // ma
                                    G_TYPE_DOUBLE,   // phase
                                    G_TYPE_STRING);  // visibility

    /* add rows to list store */
    num = g_slist_length (pass->details);

    
    for (i = 0; i < num; i++) {

        detail = PASS_DETAIL(g_slist_nth_data (pass->details, i));

        gtk_list_store_append (liststore, &item);
        gtk_list_store_set (liststore, &item,
                            SINGLE_PASS_COL_TIME, detail->time,
                            SINGLE_PASS_COL_AZ, detail->az,
                            SINGLE_PASS_COL_EL, detail->el,
                            SINGLE_PASS_COL_RANGE, detail->range,
                            SINGLE_PASS_COL_RANGE_RATE, detail->range_rate,
                            SINGLE_PASS_COL_LAT, detail->lat,
                            SINGLE_PASS_COL_LON, detail->lon,
                            SINGLE_PASS_COL_FOOTPRINT, detail->footprint,
                            SINGLE_PASS_COL_ALT, detail->alt,
                            SINGLE_PASS_COL_VEL, detail->velo,
                            SINGLE_PASS_COL_MA, detail->ma,
                            SINGLE_PASS_COL_PHASE, detail->phase,
                            -1);

        /*     SINGLE_PASS_COL_RA */
        /*     SINGLE_PASS_COL_DEC */
        if (flags & (SINGLE_PASS_FLAG_RA | SINGLE_PASS_FLAG_DEC)) {

            Calc_RADec (detail->time, detail->az, detail->el, qth, &astro);

            ra = Degrees(astro.ra);
            dec = Degrees(astro.dec);

            gtk_list_store_set (liststore, &item,
                                SINGLE_PASS_COL_RA, ra,
                                SINGLE_PASS_COL_DEC, dec,
                                -1);
        }
        
        /*     SINGLE_PASS_COL_SSP */
        if (flags & SINGLE_PASS_FLAG_SSP) {
            
            buff = g_try_malloc (7);

            retcode = longlat2locator (detail->lon, detail->lat, buff, 3);
            if (retcode == RIG_OK) {
                buff[6] = '\0';
                gtk_list_store_set (liststore, &item,
                                    SINGLE_PASS_COL_SSP, buff,
                                    -1);
            }
            g_free (buff);
        }
        
        /*      SINGLE_PASS_COL_DOPPLER */
        if (flags & SINGLE_PASS_FLAG_DOPPLER) {
            doppler = -100.0e06 * (detail->range_rate / 299792.4580); // Hz
            gtk_list_store_set (liststore, &item,
                                SINGLE_PASS_COL_DOPPLER, doppler,
                                -1);                        
        }

        /*     SINGLE_PASS_COL_LOSS */
        if (flags & SINGLE_PASS_FLAG_LOSS) {
            loss = 72.4 + 20.0*log10(detail->range);               // dB
            gtk_list_store_set (liststore, &item,
                                SINGLE_PASS_COL_LOSS, loss,
                                -1);                        
        }

        /*     SINGLE_PASS_COL_DELAY */
        if (flags & SINGLE_PASS_FLAG_DELAY) {
            delay   = detail->range / 299.7924580;         // msec 
            gtk_list_store_set (liststore, &item,
                                SINGLE_PASS_COL_DELAY, delay,
                                -1);                        
        }

        /*     SINGLE_PASS_COL_VIS */
        if (flags & SINGLE_PASS_FLAG_VIS) {
            buff = g_strdup_printf ("%c", vis_to_chr (detail->vis));
            gtk_list_store_set (liststore, &item,
                                SINGLE_PASS_COL_VIS, buff,
                                -1);                        
            g_free (buff);
        }

    }

    /* connect model to tree view */
    gtk_tree_view_set_model (GTK_TREE_VIEW (list), GTK_TREE_MODEL (liststore));
    g_object_unref (liststore);

    /* scrolled window */
    swin = gtk_scrolled_window_new (NULL, NULL);
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
                                    GTK_POLICY_NEVER,
                                    GTK_POLICY_AUTOMATIC);



    gtk_container_add (GTK_CONTAINER (swin), list);


    /* create notebook and add pages */
    notebook = gtk_notebook_new ();
    image = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, GTK_ICON_SIZE_MENU);
    hbox = gtk_hbox_new (FALSE, 0);
    gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0);
    gtk_box_pack_start (GTK_BOX (hbox), gtk_label_new (_("Data")), FALSE, TRUE, 5);
    gtk_widget_show_all (hbox);
    gtk_notebook_append_page (GTK_NOTEBOOK (notebook), swin, hbox);

    /* polar plot */
    polar = gtk_polar_plot_new (qth, pass);
    buff = icon_file_name ("gpredict-polar-small.png");
    image = gtk_image_new_from_file (buff);
    g_free (buff);
    hbox = gtk_hbox_new (FALSE, 0);
    gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0);
    gtk_box_pack_start (GTK_BOX (hbox), gtk_label_new (_("Polar")), FALSE, TRUE, 5);
    gtk_widget_show_all (hbox);
    gtk_notebook_append_page (GTK_NOTEBOOK (notebook), polar, hbox);

    /* Az/El plot */
    azel = gtk_azel_plot_new (qth, pass);
    buff = icon_file_name ("gpredict-azel-small.png");
    image = gtk_image_new_from_file (buff);
    g_free (buff);
    hbox = gtk_hbox_new (FALSE, 0);
    gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0);
    gtk_box_pack_start (GTK_BOX (hbox), gtk_label_new (_("Az/El")), FALSE, TRUE, 5);
    gtk_widget_show_all (hbox);
    gtk_notebook_append_page (GTK_NOTEBOOK (notebook), azel, hbox);


    /* create dialog */
    title = g_strdup_printf (_("Pass details for %s (orbit %d)"),
                             satname, pass->orbit);

    /* use NULL as parent to avoid conflict when using undocked windows
       as parents.
    */
    dialog = gtk_dialog_new_with_buttons (title,
                                          GTK_WINDOW (toplevel),
                                          GTK_DIALOG_DESTROY_WITH_PARENT,
                                          GTK_STOCK_PRINT, RESPONSE_PRINT,
                                          GTK_STOCK_SAVE, RESPONSE_SAVE,
                                          GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
                                          NULL);
    g_free (title);

    /* Make Close button default */
    gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);

    /* window icon */
    buff = icon_file_name ("gpredict-sat-list.png");
    gtk_window_set_icon_from_file (GTK_WINDOW (dialog), buff, NULL);
    g_free (buff);

    /* allow interaction with other windows */
    gtk_window_set_modal (GTK_WINDOW (dialog), FALSE);

    g_object_set_data (G_OBJECT (dialog), "sat", (gpointer) satname);
    g_object_set_data (G_OBJECT (dialog), "qth", qth);
    g_object_set_data (G_OBJECT (dialog), "pass", pass);


    g_signal_connect (dialog, "response",
                      G_CALLBACK (single_pass_response), NULL);
    g_signal_connect (dialog, "destroy",
                      G_CALLBACK (single_pass_dialog_destroy), NULL);
    g_signal_connect (dialog, "delete_event",
                      G_CALLBACK (single_pass_dialog_delete), NULL);    


    gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area(GTK_DIALOG(dialog))), notebook);

    gtk_window_set_default_size (GTK_WINDOW (dialog), -1, 300);
    gtk_widget_show_all (dialog);

}