]> git.itanic.dy.fi Git - maemo-mapper/blob - src/aprs_display.c
Added basic APRS support - Can be disabled by removing definition of INCLUDE_APRS
[maemo-mapper] / src / aprs_display.c
1 /*
2  * Created by Rob Williams - 10 Aug 2008
3  * 
4  * This file is part of Maemo Mapper.
5  *
6  * Maemo Mapper is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Maemo Mapper is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Maemo Mapper.  If not, see <http://www.gnu.org/licenses/>.
18  * 
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #    include "config.h"
23 #endif
24
25 #ifdef INCLUDE_APRS
26
27 #include "aprs_display.h"
28 #include "aprs_message.h"
29 #include "types.h"
30 #include "aprs.h"
31
32 #define _GNU_SOURCE
33
34 #include <stdlib.h>
35 #include <string.h>
36 #include <math.h>
37 #include <dbus/dbus-glib.h>
38 #include <bt-dbus.h>
39 #include <gconf/gconf-client.h>
40
41 #ifndef LEGACY
42 #    include <hildon/hildon-help.h>
43 #    include <hildon/hildon-note.h>
44 #    include <hildon/hildon-color-button.h>
45 #    include <hildon/hildon-file-chooser-dialog.h>
46 #    include <hildon/hildon-number-editor.h>
47 #    include <hildon/hildon-banner.h>
48 #else
49 #    include <osso-helplib.h>
50 #    include <hildon-widgets/hildon-note.h>
51 #    include <hildon-widgets/hildon-color-button.h>
52 #    include <hildon-widgets/hildon-file-chooser-dialog.h>
53 #    include <hildon-widgets/hildon-number-editor.h>
54 #    include <hildon-widgets/hildon-banner.h>
55 #    include <hildon-widgets/hildon-input-mode-hint.h>
56 #endif
57
58 #include "types.h"
59 #include "data.h"
60 #include "defines.h"
61
62 #include "gps.h"
63 #include "display.h"
64 #include "gdk-pixbuf-rotate.h"
65 #include "maps.h"
66 #include "marshal.h"
67 #include "poi.h"
68 #include "settings.h"
69 #include "util.h"
70
71 extern AprsDataRow *n_first;
72
73 typedef struct _AprsStationSelectInfo AprsStationSelectInfo;
74 struct _AprsStationSelectInfo
75 {
76     GtkWidget *dialog;
77     GtkWidget *tree_view;
78     gint      column_index;
79     gchar     *call_sign;
80 };
81
82 static AprsStationSelectInfo selected_station;
83
84
85
86 double convert_lat_l2d(long lat);
87 double convert_lon_l2d(long lon);
88 static gboolean panto_station(GtkWidget *widget, AprsStationSelectInfo *aprs_station_sel);
89
90 void convert_temp_f_to_c(gchar * f, gchar ** c)
91 {
92         *c = g_strdup("        ");
93         
94         gdouble df = 0.0;
95         gdouble dc = 0.0;
96         
97         // Convert fahrenheit to fahrenheit (double)
98         df = g_ascii_strtod ( f, (gchar*)(f + strlen(f)));
99         
100         // Convert ff to fc
101         dc = 5*((df - 32.0)/9);
102         
103         // Convert fc to celsius
104         snprintf(*c, 8, "%0.1f°C", dc);
105 }
106
107 void setup_aprs_basic_wx_display_page(GtkWidget *notebook, AprsDataRow *p_station)
108 {
109     GtkWidget *table;
110     GtkWidget *label;
111     
112
113     gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
114         table = gtk_table_new(4/*rows*/, 4/*columns*/, FALSE/*All cells same size*/),
115         label = gtk_label_new(_("WX")));
116
117     /* Last update */    
118     gchar last_update_time[26];
119     
120     gtk_table_attach(GTK_TABLE(table),
121         label = gtk_label_new("Updated:"),
122             0, 1, 0, 1, GTK_FILL, 0, 2, 4);
123     gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
124
125     
126     
127     if(p_station->weather_data && p_station->weather_data->wx_sec_time)
128     {
129          strftime(last_update_time, 25, "%x %X", localtime(&p_station->weather_data->wx_sec_time));
130     }
131     else
132     {
133         snprintf(last_update_time, 25, " ");
134     }
135     
136     gtk_table_attach(GTK_TABLE(table),
137                 label = gtk_label_new( last_update_time ),
138             1, 4, 0, 1, GTK_EXPAND |GTK_FILL, 0, 2, 4);
139     gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
140         
141     
142     /* Temperature */
143     gchar * temp = NULL;
144     
145     gtk_table_attach(GTK_TABLE(table),
146         label = gtk_label_new("Temp:"),
147             0, 1, 1, 2, GTK_FILL, 0, 2, 4);
148     gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
149
150     
151     if(p_station->weather_data && p_station->weather_data->wx_temp)
152     {
153         convert_temp_f_to_c(p_station->weather_data->wx_temp, &temp);
154     }
155     else
156     {
157         temp = g_strdup("");
158     }
159     
160     gtk_table_attach(GTK_TABLE(table),
161                 label = gtk_label_new( temp ),
162             1, 2, 1, 2, GTK_FILL, 0, 2, 4);
163     gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
164     
165     g_free(temp);
166     
167     /////////////////
168
169     gtk_table_attach(GTK_TABLE(table),
170         label = gtk_label_new( (p_station->weather_data->wx_storm ? "SEVERE STORM" : "")  ),
171             2, 4, 1, 2, GTK_EXPAND |GTK_FILL, 0, 2, 4);
172     gtk_misc_set_alignment(GTK_MISC(label), 0.5f, 0.5f);
173
174
175     /////
176     gchar course[7];
177     gtk_table_attach(GTK_TABLE(table),
178         label = gtk_label_new( "Wind course:"  ),
179             0, 1, 2, 3, GTK_FILL, 0, 2, 4);
180     gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
181     
182     snprintf(course, 6, "%0.f°", 
183                 g_ascii_strtod (p_station->weather_data->wx_course, p_station->weather_data->wx_course + strlen(p_station->weather_data->wx_course))
184                 );
185     gtk_table_attach(GTK_TABLE(table),
186         label = gtk_label_new( course ),
187             1, 2, 2, 3, GTK_FILL, 0, 2, 4);
188     gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
189     
190 //    g_free(course);
191     
192     /////
193     gchar speed[15];
194     gtk_table_attach(GTK_TABLE(table),
195         label = gtk_label_new( "Wind speed:"  ),
196             2, 3, 2, 3, GTK_FILL, 0, 2, 4);
197     gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
198
199     snprintf(speed, 14, "%0.f->%0.f MPH",
200                 g_ascii_strtod (p_station->weather_data->wx_speed, p_station->weather_data->wx_speed + strlen(p_station->weather_data->wx_speed)),
201                 g_ascii_strtod (p_station->weather_data->wx_gust, p_station->weather_data->wx_gust + strlen(p_station->weather_data->wx_gust))
202                 );
203     gtk_table_attach(GTK_TABLE(table),
204         label = gtk_label_new( speed ),
205             3, 4, 2, 3, GTK_FILL, 0, 2, 4);
206     gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
207     
208   
209
210     
211     /////
212     gchar rain_ph[17];
213     gchar rain_total[17];
214     
215     gtk_table_attach(GTK_TABLE(table),
216         label = gtk_label_new( "Rain fall:"  ),
217             0, 1, 3, 4, GTK_FILL, 0, 2, 4);
218     gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
219
220     if(p_station->weather_data->wx_rain)
221     {
222             snprintf(rain_ph, 16, "%0.f \"/hr",
223                         g_ascii_strtod (p_station->weather_data->wx_rain, p_station->weather_data->wx_rain + strlen(p_station->weather_data->wx_rain))
224                         );
225     }
226     else
227     {
228         snprintf(rain_ph, 1, " ");
229     }
230     gtk_table_attach(GTK_TABLE(table),
231         label = gtk_label_new( rain_ph ),
232             1, 2, 3, 4, GTK_FILL, 0, 2, 4);
233     gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
234
235     
236     gtk_table_attach(GTK_TABLE(table),
237         label = gtk_label_new( "Total:"  ),
238             2, 3, 3, 4, GTK_FILL, 0, 2, 4);
239     gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
240
241     if(p_station->weather_data->wx_rain_total)
242     {
243             snprintf(rain_total, 16, "%0.f \"",
244                         g_ascii_strtod (p_station->weather_data->wx_rain_total, p_station->weather_data->wx_rain_total + strlen(p_station->weather_data->wx_rain_total))
245                         );
246     }
247     else
248     {
249         snprintf(rain_total, 1, " ");
250     }
251     gtk_table_attach(GTK_TABLE(table),
252         label = gtk_label_new( rain_total ),
253             3, 4, 3, 4, GTK_FILL, 0, 2, 4);
254     gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
255     
256     
257     
258     /*
259
260     char    wx_hurricane_radius[4];  //nautical miles       3
261     char    wx_trop_storm_radius[4]; //nautical miles       3
262     char    wx_whole_gale_radius[4]; // nautical miles      3
263     char    wx_snow[6];         // in inches/24h            3
264     char    wx_prec_24[10];     // in hundredths inch/day   3
265     char    wx_prec_00[10];     // in hundredths inch       3
266     char    wx_hum[5];          // in %                     3
267     char    wx_baro[10];        // in hPa                   6
268     char    wx_fuel_temp[5];    // in °F                    3
269     char    wx_fuel_moisture[5];// in %                     2
270     char    wx_type;
271     char    wx_station[MAX_WXSTATION];
272 */
273
274 }
275
276 void setup_aprs_moving_display_page(GtkWidget *notebook, AprsDataRow *p_station)
277 {
278     GtkWidget *table;
279     GtkWidget *label;
280
281     gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
282         table = gtk_table_new(4/*rows*/, 4/*columns*/, FALSE/*All cells same size*/),
283         label = gtk_label_new(_("Moving")));
284
285
286     ////////////
287     gtk_table_attach(GTK_TABLE(table),
288         label = gtk_label_new("Speed:"),
289             0, 1, 0, 1, GTK_FILL, 0, 2, 4);
290     gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
291
292   
293     gchar speed[15];
294     
295 //    snprintf(speed, sizeof(speed), "%.01f %s", atof(p_station->speed) * UNITS_CONVERT[_units], 
296 //              UNITS_ENUM_TEXT[_units]);
297     
298     if(_units == UNITS_NM)
299         snprintf(speed, sizeof(speed), "%.01f nmph", atof(p_station->speed));
300     else if(_units == UNITS_KM)
301         snprintf(speed, sizeof(speed), "%.01f kph", atof(p_station->speed)*1.852);
302     else if(_units == UNITS_MI)
303         snprintf(speed, sizeof(speed), "%.01f mph", atof(p_station->speed)*1.1508);
304
305     
306     gtk_table_attach(GTK_TABLE(table),
307                 label = gtk_label_new( speed ),
308             1, 2, 0, 1, GTK_FILL, 0, 2, 4);
309     gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
310     
311     
312
313     ////////////
314     gtk_table_attach(GTK_TABLE(table),
315         label = gtk_label_new("Course:"),
316             0, 1, 1, 2, GTK_FILL, 0, 2, 4);
317     gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
318
319     
320     gtk_table_attach(GTK_TABLE(table),
321                 label = gtk_label_new( p_station->course ),
322             1, 2, 1, 2, GTK_FILL, 0, 2, 4);
323     gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
324     
325     ////////////
326     gtk_table_attach(GTK_TABLE(table),
327         label = gtk_label_new("Alt (m):"),
328             0, 1, 2, 3, GTK_FILL, 0, 2, 4);
329     gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
330
331     
332     gtk_table_attach(GTK_TABLE(table),
333                 label = gtk_label_new( p_station->altitude ),
334             1, 2, 2, 3, GTK_FILL, 0, 2, 4);
335     gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
336
337     ////////////
338     gtk_table_attach(GTK_TABLE(table),
339         label = gtk_label_new("Bearing:"),
340             0, 1, 3, 4, GTK_FILL, 0, 2, 4);
341     gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
342
343     
344     gtk_table_attach(GTK_TABLE(table),
345                 label = gtk_label_new( p_station->bearing ),
346             1, 2, 3, 4, GTK_FILL, 0, 2, 4);
347     
348     /*
349     GdkPixmap *pixmap=gdk_pixmap_new(table->window,100,100,16);
350     gdk_drawable_set_colormap (pixmap,gdk_colormap_get_system ());
351
352
353     GtkWidget *image = NULL;
354     GdkColor color;
355     GdkGC * gc;
356     gc = gdk_gc_new(pixmap);
357     color.red = 0;
358     color.green = 0;
359     color.blue = 0;
360
361     gdk_gc_set_foreground(gc, &color);
362     
363     color.red = 255;
364     color.green = 255;
365     color.blue = 255;
366     gdk_gc_set_background(gc, &color);
367
368     
369     gdk_gc_set_line_attributes(gc, _draw_width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
370             
371         gdk_draw_arc (
372                         pixmap, 
373                         gc,
374                         FALSE,
375                         2, 2,
376                         96, 96,
377                         0, 360*64
378                         );
379         
380         gdouble heading = deg2rad(atof(p_station->course));
381         gint y = (gint)(48.0 * cosf(heading) );
382         gint x = (gint)(48.0 * sinf(heading) );
383         
384         gdk_draw_line (
385                         pixmap, 
386                         gc,
387                         50, 50,
388                         50+x, 50-y);
389           
390     gtk_table_attach(GTK_TABLE(table),
391                 image = gtk_image_new_from_pixmap(pixmap, NULL), 
392                 2, 3, 0, 4, GTK_SHRINK, GTK_SHRINK, 2, 4);
393     gtk_misc_set_alignment(GTK_MISC(image), 1.0f, 0.5f);
394      */ 
395     
396 //    g_object_unref(image);
397 //    gdk_pixmap_unref(pixmap);
398 }
399
400
401 void setup_aprs_station_stats_page(GtkWidget *notebook, AprsDataRow *p_station)
402 {
403     GtkWidget *table;
404     GtkWidget *label;
405     gchar distance[15];
406     gchar lat[15], lon[15];
407     gchar course_deg[9];
408
409     
410     gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
411         table = gtk_table_new(4/*rows*/, 5/*columns*/, FALSE/*All cells same size*/),
412         label = gtk_label_new(_("Location")));
413
414     ////////////
415     
416     course_deg[0] = '\0';
417     distance[0] = '\0';
418     lat[0] = '\0';
419     lon[0] = '\0';
420     
421
422         if(p_station->coord_lat != 0 || p_station->coord_lon != 0)
423         {
424                 gdouble d_lat = convert_lat_l2d(p_station->coord_lat);
425                 gdouble d_lon = convert_lon_l2d(p_station->coord_lon);
426
427                 format_lat_lon(d_lat, d_lon, lat, lon);
428             
429                 gfloat dist = (float)calculate_distance(_gps.lat, _gps.lon, d_lat, d_lon);
430                 
431                 
432                 snprintf(distance, sizeof(distance), "%.01f %s", dist * UNITS_CONVERT[_units], UNITS_ENUM_TEXT[_units]);
433
434                 snprintf(course_deg,  sizeof(course_deg),
435                                 "%.01f°",
436                                 calculate_bearing(_gps.lat, _gps.lon, d_lat, d_lon));
437         }
438
439     /* Last heard */    
440     gchar last_update_time[26];
441     
442     gtk_table_attach(GTK_TABLE(table),
443         label = gtk_label_new("Last Heard:"),
444             0, 1, 4, 5, GTK_FILL, 0, 2, 4);
445     gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
446
447     
448     
449     if(p_station->sec_heard)
450     {
451          strftime(last_update_time, 25, "%x %X", localtime(&p_station->sec_heard));
452     }
453     else
454     {
455         snprintf(last_update_time, 25, " ");
456     }
457     
458     gtk_table_attach(GTK_TABLE(table),
459                 label = gtk_label_new( last_update_time ),
460             1, 4, 4, 5, GTK_FILL, 0, 2, 4);
461     gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
462         
463
464     
465         ////////////
466         gtk_table_attach(GTK_TABLE(table),
467         label = gtk_label_new("Location:"),
468             0, 1, 1, 2, GTK_FILL, 0, 2, 4);
469     gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
470
471     gtk_table_attach(GTK_TABLE(table),
472                 label = gtk_label_new( lat ),
473             1, 3, 1, 2, GTK_EXPAND |GTK_FILL, 0, 2, 4);
474     gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
475
476     gtk_table_attach(GTK_TABLE(table),
477                 label = gtk_label_new( lon ),
478             3, 5, 1, 2, GTK_EXPAND |GTK_FILL, 0, 2, 4);
479     gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
480
481     ////////////
482     
483     gtk_table_attach(GTK_TABLE(table),
484         label = gtk_label_new(""),
485             0, 5, 2, 3, GTK_FILL, 0, 2, 4);
486     gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
487
488     
489     ////////////
490     gtk_table_attach(GTK_TABLE(table),
491         label = gtk_label_new("Distance:"),
492             0, 1, 3, 4, GTK_FILL, 0, 2, 4);
493     gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
494
495     gtk_table_attach(GTK_TABLE(table),
496                 label = gtk_label_new( distance ),
497             1, 2, 3, 4, GTK_FILL, 0, 2, 4);
498     gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
499
500     //
501     
502     gtk_table_attach(GTK_TABLE(table),
503         label = gtk_label_new("Bearing:"),
504             2, 4, 3, 4, GTK_EXPAND |GTK_FILL, 0, 2, 4);
505     gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
506
507     gtk_table_attach(GTK_TABLE(table),
508                 label = gtk_label_new( course_deg ),
509             4, 5, 3, 4, GTK_FILL, 0, 2, 4);
510     gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
511  
512
513     ////////////
514     
515 }
516
517
518 void setup_aprs_basic_display_page(GtkWidget *notebook, AprsDataRow *p_station)
519 {
520     GtkWidget *table;
521     GtkWidget *label;
522
523     gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
524         table = gtk_table_new(5/*rows*/, 4/*columns*/, FALSE/*All cells same size*/),
525         label = gtk_label_new(_("Basic")));
526
527     /* Callsign. */
528     // Label
529     
530     gtk_table_attach(GTK_TABLE(table),
531         label = gtk_label_new("Callsign:"),
532             0, 1, 0, 1, GTK_FILL, 0, 2, 4);
533     gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
534
535     
536     
537     gtk_table_attach(GTK_TABLE(table),
538
539                 label = gtk_label_new( p_station->call_sign ),
540             1, 2, 0, 1, GTK_FILL, 0, 2, 4);
541     gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
542
543     
544     gtk_table_attach(GTK_TABLE(table),
545         label = gtk_label_new("Packets:"),
546             2, 3, 0, 1, GTK_FILL, 0, 2, 4);
547     gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
548
549     
550     gchar packets[5];
551     snprintf(packets, 4, "%u", p_station->num_packets);
552     
553     gtk_table_attach(GTK_TABLE(table),
554                 label = gtk_label_new( packets ),
555             3, 4, 0, 1, GTK_FILL, 0, 2, 4);
556     gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
557     
558     gtk_table_attach(GTK_TABLE(table),
559                 label  = gtk_label_new("Comment:"),
560             0, 1, 1, 3, GTK_FILL, 0, 2, 4);
561     gtk_misc_set_alignment(GTK_MISC(label ), 1.f, 0.5f);
562     
563     gchar * comment = NULL;
564     
565     
566     if(p_station->comment_data && p_station->comment_data->text_ptr)
567     {
568         comment = g_strdup(p_station->comment_data->text_ptr);
569     }
570     else
571     {
572         comment = g_strdup("");
573     }
574     
575     gtk_table_attach(GTK_TABLE(table),
576                 label  = gtk_label_new(comment),
577             1, 4, 1, 3, GTK_EXPAND |GTK_FILL, 0, 2, 4);
578     gtk_misc_set_alignment(GTK_MISC(label ), 0.f, 0.5f);
579     gtk_label_set_width_chars(label, 30);
580     
581     
582     
583     //// 
584
585     gtk_table_attach(GTK_TABLE(table),
586                 label  = gtk_label_new("Status:"),
587             0, 1, 3, 4, GTK_FILL, 0, 2, 4);
588     gtk_misc_set_alignment(GTK_MISC(label ), 1.f, 0.5f);
589     
590     gchar * status = NULL;
591     
592     
593     if(p_station->status_data && p_station->status_data->text_ptr)
594     {
595         status = g_strdup(p_station->status_data->text_ptr);
596     }
597     else
598     {
599         status = g_strdup("");
600     }
601     
602     gtk_table_attach(GTK_TABLE(table),
603                 label  = gtk_label_new(status),
604             1, 4, 3, 4, GTK_FILL, 0, 2, 4);
605     gtk_misc_set_alignment(GTK_MISC(label ), 0.f, 0.5f);
606     
607     
608     //// 
609
610     gtk_table_attach(GTK_TABLE(table),
611                 label  = gtk_label_new("Path:"),
612             0, 1, 4, 5, GTK_FILL, 0, 2, 4);
613     gtk_misc_set_alignment(GTK_MISC(label ), 1.f, 0.5f);
614     
615     gchar * path = NULL;
616     
617     if(p_station->node_path_ptr)
618     {
619         path = g_strdup(p_station->node_path_ptr);
620     }
621     else
622     {
623         path = g_strdup("");
624     }
625     
626     gtk_table_attach(GTK_TABLE(table),
627                 label  = gtk_label_new(path),
628             1, 4, 4, 5, GTK_FILL, 0, 2, 4);
629     gtk_misc_set_alignment(GTK_MISC(label ), 0.f, 0.5f);
630         
631     
632
633     
634 }
635
636
637
638 void ShowAprsStationPopup(AprsDataRow *p_station)
639 {
640         GtkWidget *dialog = NULL;
641         GtkWidget *notebook = NULL;
642         GtkWidget *btn_panto = NULL;
643
644         dialog = gtk_dialog_new_with_buttons(_("Station Details"),
645                 GTK_WINDOW(_window), GTK_DIALOG_MODAL,
646                 GTK_STOCK_CLOSE, GTK_RESPONSE_ACCEPT,
647 //                "Send Message...", GTK_RESPONSE_ACCEPT,
648                 NULL);
649         
650     
651     gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
652                 btn_panto = gtk_button_new_with_mnemonic(_("C_entre Map...")));
653             
654     
655     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
656             notebook = gtk_notebook_new(), TRUE, TRUE, 0);
657         
658
659     selected_station.dialog = NULL;
660     selected_station.tree_view = NULL;
661     selected_station.column_index = 0;
662     selected_station.call_sign = p_station->call_sign;
663     
664     g_signal_connect(G_OBJECT(btn_panto), "clicked",
665                 G_CALLBACK(panto_station), &selected_station);
666     
667     
668         setup_aprs_basic_display_page(notebook, p_station);
669         
670         
671         if(p_station->weather_data )
672                 setup_aprs_basic_wx_display_page(notebook, p_station);
673
674         
675         
676         if( ( p_station->flag & ST_MOVING) == ST_MOVING){
677                 setup_aprs_moving_display_page(notebook, p_station);
678         }
679         
680         
681         
682         setup_aprs_station_stats_page(notebook, p_station);
683         
684     gtk_widget_show_all(dialog);
685     gtk_dialog_run(GTK_DIALOG(dialog));  
686     gtk_widget_hide(dialog);
687     
688
689 }
690
691
692
693
694
695 void list_stations()
696 {
697     static GtkWidget *dialog = NULL;
698     static GtkWidget *list = NULL;
699     static GtkWidget *sw = NULL;
700     static GtkWidget *btn_panto = NULL;
701     static GtkTreeViewColumn *column = NULL;
702     static GtkCellRenderer *renderer = NULL;
703     GtkListStore *store = NULL;
704     GtkTreeIter iter;
705     gint station_count = 0;
706
707     gint num_cats = 0;
708
709     printf("%s()\n", __PRETTY_FUNCTION__);
710     
711     typedef enum
712     {
713         STATION_CALLSIGN,
714         STATION_DISTANCE,
715         STATION_BEARING,
716         STATION_COMMENT,
717         STATION_DISTANCE_NUM,
718         STATION_NUM_COLUMNS
719     } StationList;
720     
721     /* Initialize store. */
722     store = gtk_list_store_new(STATION_NUM_COLUMNS,
723                 G_TYPE_STRING,
724                 G_TYPE_STRING,
725                 G_TYPE_STRING,
726                 G_TYPE_STRING,
727                 G_TYPE_DOUBLE);/* Category Label */
728  
729     AprsDataRow *p_station = n_first;
730
731     while ( (p_station) != NULL) 
732     {
733         station_count++;
734         
735         gchar * comment = NULL;
736         gchar * callsign = g_strdup(p_station->call_sign);
737         gchar course_deg[8];
738         gchar * formatted_distance = NULL;
739         gdouble distance = 0;
740         
741         course_deg[0] = '\0';
742          
743         
744         if(p_station->coord_lat != 0 && p_station->coord_lon != 0)
745         {
746                 distance = distance_from_my_station(callsign, course_deg, sizeof(course_deg));
747                 
748                 if(_units == UNITS_KM)
749                         formatted_distance = g_strdup_printf("%.01f km", distance);
750                 else if(_units == UNITS_MI)
751                         formatted_distance = g_strdup_printf("%.01f miles", distance);
752                 else if(_units == UNITS_NM)
753                         formatted_distance = g_strdup_printf("%.01f nm", distance); 
754         }
755         else
756         {
757                 formatted_distance = g_strdup_printf("");
758         }
759         
760         if(p_station->comment_data) comment = g_strdup(p_station->comment_data->text_ptr);
761         else comment = g_strdup("");
762         
763   
764         gtk_list_store_append(store, &iter);
765         gtk_list_store_set(store, &iter,
766                         STATION_CALLSIGN, callsign,
767                         STATION_DISTANCE, formatted_distance,
768                         STATION_BEARING, course_deg,
769                         STATION_COMMENT, comment,
770                         STATION_DISTANCE_NUM, distance,
771                 -1);
772         num_cats++;
773         
774         g_free(comment);
775         g_free(callsign);
776         g_free(formatted_distance);
777         
778         (p_station) = (p_station)->n_next;  // Next element in list
779     } // End of while loop
780
781     gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), STATION_DISTANCE_NUM, GTK_SORT_ASCENDING);
782     
783
784
785     if(dialog == NULL)
786     {
787         dialog = gtk_dialog_new_with_buttons(_("Stations"),
788                 GTK_WINDOW(_window), GTK_DIALOG_MODAL,
789                 "Details", GTK_RESPONSE_ACCEPT,
790                 GTK_STOCK_CLOSE, GTK_RESPONSE_REJECT,
791                 NULL);
792
793
794         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
795                         btn_panto = gtk_button_new_with_mnemonic(_("C_entre Map...")));
796                 
797         
798         
799         gtk_window_set_default_size(GTK_WINDOW(dialog), 500, 300);
800
801         sw = gtk_scrolled_window_new (NULL, NULL);
802         
803         gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
804                 GTK_SHADOW_ETCHED_IN);
805         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
806                 GTK_POLICY_NEVER,
807                 GTK_POLICY_AUTOMATIC);
808         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
809                 sw, TRUE, TRUE, 0);
810
811         list = gtk_tree_view_new();
812         gtk_container_add(GTK_CONTAINER(sw), list);
813
814         gtk_tree_selection_set_mode(
815                 gtk_tree_view_get_selection(GTK_TREE_VIEW(list)),
816                 GTK_SELECTION_SINGLE);
817         gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), TRUE);
818
819         
820         //////
821         renderer = gtk_cell_renderer_text_new();
822         column = gtk_tree_view_column_new_with_attributes(
823                 _("Callsign"), renderer, "text", STATION_CALLSIGN, NULL);
824         gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
825
826         ///////
827         renderer = gtk_cell_renderer_text_new();
828         column = gtk_tree_view_column_new_with_attributes(
829                 _("Distance"), renderer, "text", STATION_DISTANCE, NULL);
830         gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
831
832         /////////
833         renderer = gtk_cell_renderer_text_new();
834         column = gtk_tree_view_column_new_with_attributes(
835                 _("Bearing"), renderer, "text", STATION_BEARING, NULL);
836         gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
837         
838
839         /////////
840         renderer = gtk_cell_renderer_text_new();
841         column = gtk_tree_view_column_new_with_attributes(
842                 _("Comment"), renderer, "text", STATION_COMMENT, NULL);
843         gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
844         
845         
846
847         selected_station.dialog = dialog;
848         selected_station.tree_view = list;
849         selected_station.call_sign = NULL;
850         selected_station.column_index = STATION_CALLSIGN;
851         
852         g_signal_connect(G_OBJECT(btn_panto), "clicked",
853                         G_CALLBACK(panto_station), &selected_station);
854                 
855     }
856
857     gtk_tree_view_set_model(GTK_TREE_VIEW(list), GTK_TREE_MODEL(store));
858     g_object_unref(G_OBJECT(store));
859
860     
861     //
862     gchar *title = g_strdup_printf("Stations (Total: %u)", station_count);
863     gtk_window_set_title(GTK_WINDOW(dialog), title);
864     g_free(title);
865     
866     gtk_widget_show_all(dialog);
867
868     while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
869     {
870
871         if(gtk_tree_selection_get_selected(
872                 gtk_tree_view_get_selection(GTK_TREE_VIEW(list)),
873                 NULL, &iter))
874         {
875                 // Find the callsign
876                 p_station = n_first;
877                 while(p_station != NULL)
878                 {
879                         gchar * callsign = NULL;
880                     gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
881                         STATION_CALLSIGN, &(callsign),
882                         -1);
883
884                     if(strcmp(p_station->call_sign,callsign) == 0)
885                         {
886                                 ShowAprsStationPopup(p_station);
887                                 break;
888                                 
889                         }
890
891                         
892                     p_station = p_station->n_next;
893                 }
894
895         }
896
897
898
899     }
900
901     gtk_widget_hide(dialog);
902
903     vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, selected);
904 }
905
906
907
908
909 static gboolean
910 send_message(GtkWidget *widget)
911 {
912         fprintf(stderr, "Send message...");
913         return FALSE;
914 }
915
916 static gboolean
917 panto_station(GtkWidget *widget, AprsStationSelectInfo *aprs_station_selected)
918 {
919     GtkTreeModel *store;
920     GtkTreeIter iter;
921     GtkTreeSelection *selection;
922         gchar * callsign = NULL;
923     AprsDataRow *p_station = n_first;
924     
925
926     printf("%s()\n", __PRETTY_FUNCTION__);
927
928     
929         if(aprs_station_selected->call_sign != NULL)
930                 callsign = aprs_station_selected->call_sign;
931         else
932         {
933                 store = gtk_tree_view_get_model(GTK_TREE_VIEW(aprs_station_selected->tree_view));
934             selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(aprs_station_selected->tree_view));
935             
936             if(gtk_tree_selection_get_selected(selection, &store, &iter))
937             {
938
939             gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
940                 aprs_station_selected->column_index, &(callsign),
941                 -1);
942
943             }
944         }
945         
946         // Now findout the location of callsign
947         
948         p_station = n_first;
949         while(p_station != NULL)
950         {
951         if(strcmp(p_station->call_sign,callsign) == 0)
952                 {
953                 if(p_station->coord_lat == 0 && p_station->coord_lon == 0)
954                 {
955                         // Invalid position
956                 }
957                 else
958                 {       
959                         gdouble d_lat = convert_lat_l2d(p_station->coord_lat);
960                         gdouble d_lon = convert_lon_l2d(p_station->coord_lon);
961                         Point unit;
962         
963                         
964                     latlon2unit(d_lat, d_lon, unit.unitx, unit.unity);
965         
966                     if(_center_mode > 0)
967                         gtk_check_menu_item_set_active(
968                                 GTK_CHECK_MENU_ITEM(_menu_view_ac_none_item), TRUE);
969         
970                     map_center_unit(unit);
971
972                 }
973         
974                 
975                         break;
976                         
977                 }
978
979         p_station = p_station->n_next;
980         }
981
982         
983                 
984     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
985     return TRUE;
986 }
987
988 void list_messages()
989 {
990         static GtkWidget *dialog = NULL;
991 //      static GtkWidget *btn_send = NULL;
992     static GtkWidget *list = NULL;
993     static GtkWidget *sw = NULL;
994     static GtkTreeViewColumn *column = NULL;
995     static GtkCellRenderer *renderer = NULL;
996     GtkListStore *store = NULL;
997         GtkTreeIter iter;
998
999
1000     printf("%s()\n", __PRETTY_FUNCTION__);
1001
1002     typedef enum
1003     {
1004         MSG_FROM,
1005         MSG_TO,
1006         MSG_TEXT,
1007         MSG_TIMESTAMP,
1008         MSG_NUM_COLUMNS
1009     } MessageList;
1010     
1011     /* Initialize store. */
1012     store = gtk_list_store_new(MSG_NUM_COLUMNS,
1013                 G_TYPE_STRING,
1014                 G_TYPE_STRING,
1015                 G_TYPE_STRING,
1016                 G_TYPE_DOUBLE);
1017
1018     
1019     // Loop through each message
1020     
1021     gint  i = 0;
1022     for (i = 0; i < msg_index_end; i++) 
1023     {
1024         gtk_list_store_append(store, &iter);
1025         gtk_list_store_set(store, &iter,
1026                         MSG_FROM, msg_data[msg_index[i]].from_call_sign,
1027                         MSG_TO,   msg_data[msg_index[i]].call_sign,
1028                         MSG_TEXT, msg_data[msg_index[i]].message_line,
1029                         MSG_TIMESTAMP, (gdouble)msg_data[msg_index[i]].sec_heard,
1030                 -1);
1031         
1032     }
1033     
1034     gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), MSG_TIMESTAMP, GTK_SORT_ASCENDING);
1035         
1036     if(dialog == NULL)
1037     {
1038         dialog = gtk_dialog_new_with_buttons(_("Messages"),
1039                 GTK_WINDOW(_window), GTK_DIALOG_MODAL,
1040                 GTK_STOCK_CLOSE, GTK_RESPONSE_REJECT,
1041                 NULL);
1042         
1043         gtk_window_set_default_size(GTK_WINDOW(dialog), 550, 300);
1044
1045 //        gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
1046 //                      btn_send = gtk_button_new_with_label(_("Send...")));
1047         
1048 //        g_signal_connect(G_OBJECT(btn_send), "clicked",
1049 //                        G_CALLBACK(send_message), dialog);
1050         
1051                 sw = gtk_scrolled_window_new (NULL, NULL);
1052                 
1053                 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
1054                         GTK_SHADOW_ETCHED_IN);
1055                 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
1056                         GTK_POLICY_NEVER,
1057                         GTK_POLICY_AUTOMATIC);
1058                 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1059                         sw, TRUE, TRUE, 0);
1060                 
1061         
1062                 list = gtk_tree_view_new();
1063                 gtk_container_add(GTK_CONTAINER(sw), list);
1064         
1065                 gtk_tree_selection_set_mode(
1066                         gtk_tree_view_get_selection(GTK_TREE_VIEW(list)),
1067                         GTK_SELECTION_SINGLE);
1068                 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), TRUE);
1069
1070         
1071
1072                 renderer = gtk_cell_renderer_text_new();
1073                 column = gtk_tree_view_column_new_with_attributes(
1074                         _("From"), renderer, "text", MSG_FROM, NULL);
1075                 gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
1076
1077                 renderer = gtk_cell_renderer_text_new();
1078                 column = gtk_tree_view_column_new_with_attributes(
1079                         _("To"), renderer, "text", MSG_TO, NULL);
1080                 gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
1081
1082                 renderer = gtk_cell_renderer_text_new();
1083                 column = gtk_tree_view_column_new_with_attributes(
1084                         _("Message"), renderer, "text", MSG_TEXT, NULL);
1085                 gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
1086                 //////
1087             }
1088
1089
1090         gtk_tree_view_set_model(GTK_TREE_VIEW(list), GTK_TREE_MODEL(store));
1091             g_object_unref(G_OBJECT(store));
1092         
1093     
1094             gtk_widget_show_all(dialog);
1095
1096             while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
1097             {
1098             }
1099
1100             gtk_widget_hide(dialog);
1101
1102             vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, selected);
1103         
1104 }
1105
1106 #endif //INCLUDE_APRS