#ifdef HAVE_CONFIG_H # include #endif #include "support.h" #include "callbacks.h" #include "globals.h" #include "poi.h" #include "converter.h" #include "interface.h" #include "util.h" #include "tile_management.h" #include #include #include #include #include #include #include #include #include #include #include #define POI_DB "poi.db" GtkListStore *list_store; gchar *my_strescape_back (const gchar *source, const gchar *exceptions); enum { COLUMN_STRING, COLUMN_INT, COLUMN_BOOLEAN, N_COLUMNS }; static GtkWidget *combobox_subcat = NULL; static gboolean new_dialog = TRUE; #define POI_DB_CREATE "CREATE TABLE poi ( \ idmd5 TEXT, lat REAL, lon REAL, visibility REAL, cat REAL, subcat REAL, \ keywords TEXT, desc TEXT, price_range REAL, extended_open REAL, \ creator TEXT, bookmarked REAL, user_rating REAL, rating REAL, user_comment TEXT);" double parse_degrees(const char *s) { float deg, min, sec; if (3 == sscanf(s, "%f %f %f", °, &min, &sec)) return deg + min/60 + sec/3600; else if (3 == sscanf(s, "%f° %f' %f\"", °, &min, &sec)) return deg + min/60 + sec/3600; else if (3 == sscanf(s, "%f°%f'%f\"", °, &min, &sec)) return deg + min/60 + sec/3600; else if (2 == sscanf(s, "%f %f", °, &min)) return deg + min/60; else if (2 == sscanf(s, "%f° %f'", °, &min)) return deg + min/60; else if (2 == sscanf(s, "%f°%f'", °, &min)) return deg + min/60; else if (1 == sscanf(s, "%f", °)) return deg; return atof(s); } static int sql_cb__poi_get(void *unused, int colc, char **colv, char **col_names) { poi_t *poi = g_new0(poi_t,1); poi->idmd5 = g_strdup(colv[0]); poi->lat_deg = atof(colv[1]); poi->lon_deg = atof(colv[2]); poi->visibility = atoi(colv[3]); poi->category = atoi(colv[4]); poi->subcategory = atoi(colv[5]); poi->keywords = g_strdup(colv[6]); poi->desc = g_strdup(colv[7]); poi->price_range = atoi(colv[8]); poi->extended_open = atoi(colv[9]); poi_list = g_slist_prepend(poi_list, poi); return 0; } static GdkPixbuf * get_poi_icon (poi_t *poi) { GdkPixbuf *icon; static GHashTable *icon_cache = NULL; static GdkPixbuf *poi_icon_default = NULL; if (!icon_cache) { /* Initialise icon-cache: */ icon_cache = g_hash_table_new (g_str_hash, g_str_equal); } if (!poi_icon_default) { /* Initialise the default POI icon: */ poi_icon_default = gdk_pixbuf_new_from_file_at_size (PACKAGE_PIXMAPS_DIR "/" PACKAGE "-poi.png", 25, 25, NULL); } icon = g_hash_table_lookup (icon_cache, poi->keywords); if (!icon) { char *icon_dir = g_build_filename (foxtrotgps_dir, "poi-icons", NULL); /* Not all characters that might be in a POI's name are suitable for use in icon-filenames, e.g.: path-separators need to be escaped so that a POI named something like "../../evil" doesn't result in us reading/writing a file somewhere where we shouldn't, and a number of characters need to be escaped to allow files to be stored on some filesystems like FAT. */ char *icon_basename = g_uri_escape_string (poi->keywords, NULL, TRUE); char *icon_path = g_build_filename (icon_dir, icon_basename, NULL); g_free (icon_basename); g_mkdir (icon_dir, 0777); g_free (icon_dir); if (!g_file_test (icon_path, G_FILE_TEST_EXISTS)) { pid_t mkvisualid_pid; int mkvisualid_status; char *autocache_dir = g_build_filename (global_home_dir, ".VisualIDs", PACKAGE, "poi-icons", NULL); g_mkdir_with_parents (autocache_dir, 0777); /* Free autocache_dir later--we need to pass it to mkvisualid, below... */ mkvisualid_pid = fork(); switch (mkvisualid_pid) { case 0: execlp ("mkvisualid", "mkvisualid", "--autocache", "--autocache-dir", autocache_dir, "--output", icon_path, "--linewidth=.1", "--outline-width=.2", /* Don't use glyph-types that are easily confused with streets: */ "--line=0", "--path=0", poi->keywords, NULL); _exit (1); /* execlp failed */ default: waitpid (mkvisualid_pid, &mkvisualid_status, 0); /* Fall through to cleanup... */ case -1: g_free (autocache_dir); } } icon = gdk_pixbuf_new_from_file_at_size (icon_path, 32, 32, NULL); /*^Note that this is slightly bigger than the `generic POI star' fallback-icon: we budget an additional 25% of the icon-radius for a border in case the icon needs one, e.g.: to ensure contrast against the map. */ g_free (icon_path); if (icon) { g_hash_table_insert (icon_cache, poi->keywords, icon); } } if (!icon) { icon = poi_icon_default; } return icon; } void paint_pois() { int pixel_x, pixel_y, x, y; float lat, lon; GSList *list; GdkColor color; static GdkGC *gc; if (!gc) gc = gdk_gc_new(pixmap); color.green = 0; color.blue = 60000; color.red = 0; gdk_gc_set_rgb_fg_color(gc, &color); if(global_show_pois) { get_pois(); for(list = poi_list; list != NULL; list = list->next) { poi_t *p = list->data; GdkPixbuf *photo_icon = get_poi_icon (p); int icon_width = gdk_pixbuf_get_width (photo_icon); int icon_height = gdk_pixbuf_get_width (photo_icon); lat = deg2rad(p->lat_deg); lon = deg2rad(p->lon_deg); pixel_x = lon2pixel(global_zoom, lon); pixel_y = lat2pixel(global_zoom, lat); x = pixel_x - global_x; y = pixel_y - global_y; p->screen_x = x; p->screen_y = y; if(!photo_icon) { gdk_draw_arc ( pixmap, gc, TRUE, x-4, y-4, 8,8, 0,23040); } else { gdk_draw_pixbuf ( pixmap, NULL, photo_icon, 0,0, x - icon_width/2, y - icon_height/2, -1, -1, GDK_RGB_DITHER_NONE, 0, 0); } gtk_widget_queue_draw_area ( map_drawable, x - icon_width/2, y - icon_height/2, icon_width, icon_height); } } } GtkListStore * create_combobox_list_store(char *list) { GtkListStore *list_store; GtkTreeIter iter; int i=0; char **array; list_store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_INT, G_TYPE_BOOLEAN); array = g_strsplit(list,"|",-1); while(array[i]) { gtk_list_store_append (list_store, &iter); gtk_list_store_set (list_store, &iter, COLUMN_STRING, array[i], COLUMN_INT, i, COLUMN_BOOLEAN, FALSE, -1); i++; } g_strfreev(array); return list_store; } void on_combobox_subcat_changed (GtkComboBox *combobox, gpointer user_data) { GtkTreeIter iter; gchar *str_data; gint int_data; gtk_combo_box_get_active_iter(combobox, &iter); gtk_tree_model_get (GTK_TREE_MODEL(list_store), &iter, COLUMN_STRING, &str_data, COLUMN_INT, &int_data, -1); } void set_combobox_subcat(GtkWidget *widget, int choice) { GtkCellRenderer *renderer; GtkWidget *vbox; char *subcat_lists[16]; subcat_lists[0] = "---"; subcat_lists[1] = _("- Please choose -|Hotel|Motel|B&B|Hostel|Camping"); subcat_lists[2] = _("- Please choose -|Bank / Exchange / ATM|Post Office|Real Estate Agency|Travel Agency|Other"); subcat_lists[3] = _("- Please choose -|Parking|Gas Station|Repair Shop|Rental|Sharing|Dealer|Radar - Speed Trap|My Car"); subcat_lists[4] = _("- Please choose -|Cinema|Theatre|Concert Hall|Opera|Casino"); subcat_lists[5] = _("- Please choose -|Pharmacy|Hospital|Doctor"); subcat_lists[6] = _("- Please choose -|Cafe|Pub|Lounge Bar|Club|Dancing|Internet Cafe|Wifi Hot Spot"); subcat_lists[7] = _("- Please choose -|Church|Mosque|Synagogue|Temple|Cemetery"); subcat_lists[8] = _("- Please choose -|Bus|Metro|Tram|Taxi|Train Station|Bike|Port|Airport"); subcat_lists[9] = _("- Please choose -|Local Food|European|Asian|American|African|Pizza|Fast Food|Take Away|Barbecue|Italian|Mexican|Indian|Japanese|French"); subcat_lists[10] = _("- Please choose -|Wifi Hotspot|ATM-Money Dispenser|Post Office/Letter Box|Laundry|Hairdresser|Other"); subcat_lists[11] = _("- Please choose -|Tourist Info|Monument|Museum|Zoo|Viewpoint|Relief Map|Other"); subcat_lists[12] = _("- Please choose -|Supermarket|Shopping Center|Clothes|Shoes|Food|Baker|Butcher|DoItYourself|Other"); subcat_lists[13] = _("- Please choose -|Arena/Stadium|Swimming Pool|Freeclimbing|Ice Skating|Golf|Geo Cache|Other"); subcat_lists[14] = _("- Please choose -|Friend|Other Cool Place"); subcat_lists[15] = _("- Please choose -|Traditional|Multi|Virtual|Letterbox Hybrid|Event|Unknown|Project Ape|Webcam|Cache In Trash Out|Earthcache|Mega-Event|GPS Adventures|Wherigo|Other"); /* * NOTE: for geocaching, should also be: * subsubcat[] = "- Please choose -|Micro|Small|Regular|Large|Virtual|Unknown|Other|"; */ vbox = lookup_widget(widget, "vbox28"); list_store = create_combobox_list_store(subcat_lists[choice]); if((!combobox_subcat || new_dialog ) && choice) { combobox_subcat = gtk_combo_box_new_with_model (GTK_TREE_MODEL(list_store)); gtk_widget_show (combobox_subcat); gtk_box_pack_start (GTK_BOX (vbox),combobox_subcat, FALSE, TRUE, 0); renderer = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox_subcat), renderer, TRUE); gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combobox_subcat), renderer, "text", 0, NULL); g_signal_connect ((gpointer) combobox_subcat, "changed", G_CALLBACK (on_combobox_subcat_changed), NULL); gtk_combo_box_set_active(GTK_COMBO_BOX(combobox_subcat), 0); gtk_box_reorder_child(GTK_BOX(vbox),combobox_subcat,6); new_dialog = FALSE; } else if (choice) { gtk_combo_box_set_model(GTK_COMBO_BOX(combobox_subcat), GTK_TREE_MODEL(list_store)); gtk_combo_box_set_active(GTK_COMBO_BOX(combobox_subcat), 0); } } void on_combobox_cat_changed(GtkComboBox *combobox) { int choice; choice = gtk_combo_box_get_active(combobox); set_combobox_subcat(GTK_WIDGET(combobox),choice); } void show_window6() { GladeXML *gladexml; GtkWidget *dialog; GtkWidget *entry14, *entry15, *combobox2; double lat, lon, lat_deg, lon_deg; char buf[64]; gladexml = glade_xml_new (gladefile, "window6", GETTEXT_PACKAGE); glade_xml_signal_autoconnect (gladexml); dialog = glade_xml_get_widget (gladexml, "window6"); g_signal_connect_swapped (dialog, "destroy", G_CALLBACK (g_object_unref), gladexml); gtk_widget_show(dialog); new_dialog = TRUE; lat = pixel2lat(global_zoom, global_y+mouse_y); lon = pixel2lon(global_zoom, global_x+mouse_x); lat_deg = rad2deg(lat); lon_deg = rad2deg(lon); entry14 = lookup_widget(dialog, "entry14"); entry15 = lookup_widget(dialog, "entry15"); g_sprintf(buf, "%f", lat_deg); gtk_entry_set_text(GTK_ENTRY(entry14), buf); g_sprintf(buf, "%f", lon_deg); gtk_entry_set_text(GTK_ENTRY(entry15), buf); combobox2 = lookup_widget(dialog, "combobox2"); gtk_combo_box_set_active(GTK_COMBO_BOX(combobox2), 0); } void set_poi(GtkWidget *dialog) { GtkComboBox *combo_box; GtkTextView *text_view; GtkTextBuffer *buffer; GtkTextIter start, end; GtkWidget *entry, *radiobutton; const char *keyword; char *desc; char *sql; char *db; int visibility, price_range = 0, extended_open; int category, subcategory; double lat_deg, lon_deg; int res; double rand1, rand2; entry = lookup_widget(dialog, "entry14"); lat_deg = parse_degrees(gtk_entry_get_text(GTK_ENTRY(entry))); entry = lookup_widget(dialog, "entry15"); lon_deg = parse_degrees(gtk_entry_get_text(GTK_ENTRY(entry))); radiobutton = lookup_widget(dialog, "radiobutton11"); visibility = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radiobutton))) ? 1 : 0; combo_box = GTK_COMBO_BOX(lookup_widget(dialog, "combobox2")); category = gtk_combo_box_get_active(combo_box); subcategory = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox_subcat)); entry = lookup_widget(dialog, "entry13"); keyword = gtk_entry_get_text(GTK_ENTRY(entry)); text_view = GTK_TEXT_VIEW(lookup_widget(dialog, "textview1")); buffer = gtk_text_view_get_buffer(text_view); gtk_text_buffer_get_start_iter (buffer, &start); gtk_text_buffer_get_end_iter (buffer, &end); desc = gtk_text_buffer_get_text(buffer, &start, &end, TRUE); radiobutton = lookup_widget(dialog, "radiobutton8"); price_range = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radiobutton))) ? 1 : price_range; radiobutton = lookup_widget(dialog, "radiobutton9"); price_range = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radiobutton))) ? 3 : price_range; radiobutton = lookup_widget(dialog, "radiobutton10"); price_range = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radiobutton))) ? 5 : price_range; radiobutton = lookup_widget(dialog, "checkbutton10"); extended_open = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radiobutton))) ? 1 : 0; rand1 = g_random_double_range (100000000,1000000000); rand2 = g_random_double_range (100000000,1000000000); db = g_strconcat(foxtrotgps_dir, "/", POI_DB, NULL); sql = sqlite3_mprintf ( "INSERT INTO poi " "(idmd5, lat, lon, visibility, cat, subcat, keywords, desc, price_range, extended_open) " "VALUES ('%.0f%.0f',%f,%f,%d,%d,%d,%Q,%Q,%d,%d)", rand1, rand2, lat_deg, lon_deg, visibility, category, subcategory, keyword, desc, price_range, extended_open); res = sql_execute(db, sql, NULL); if(res==1) { sql_execute(db, POI_DB_CREATE, NULL); sql_execute(db, sql, NULL); } g_free(desc); sqlite3_free (sql); gtk_widget_destroy(dialog); global_poi_cat = category; } void update_poi(GtkWidget *dialog) { GtkTextView *text_view; GtkTextBuffer *buffer; GtkTextIter start, end; GtkWidget *entry, *widget; const char *keyword, *idmd5; char *desc; char *sql; char *db; double lat_deg, lon_deg; int res; widget = lookup_widget(dialog, "label126"); idmd5 = gtk_label_get_text(GTK_LABEL(widget)); entry = lookup_widget(dialog, "entry17"); lat_deg = parse_degrees(gtk_entry_get_text(GTK_ENTRY(entry))); entry = lookup_widget(dialog, "entry18"); lon_deg = parse_degrees(gtk_entry_get_text(GTK_ENTRY(entry))); entry = lookup_widget(dialog, "entry19"); keyword = gtk_entry_get_text(GTK_ENTRY(entry)); text_view = GTK_TEXT_VIEW(lookup_widget(dialog, "textview2")); buffer = gtk_text_view_get_buffer(text_view); gtk_text_buffer_get_start_iter (buffer, &start); gtk_text_buffer_get_end_iter (buffer, &end); desc = gtk_text_buffer_get_text(buffer, &start, &end, TRUE); db = g_strconcat(foxtrotgps_dir, "/", POI_DB, NULL); sql = sqlite3_mprintf ( "UPDATE " "poi " "SET " "lat=%f," "lon=%f," "keywords=%Q," "desc=%Q" "WHERE " "idmd5='%s'" , lat_deg, lon_deg, keyword, desc, idmd5); res = sql_execute(db, sql, NULL); if(res==1) { sql_execute(db, POI_DB_CREATE, NULL); sql_execute(db, sql, NULL); } g_free(desc); sqlite3_free (sql); gtk_widget_destroy(dialog); } void delete_poi(poi_t *p) { char *db; char *sql; int res; db = g_strconcat(foxtrotgps_dir, "/", POI_DB, NULL); sql = g_strdup_printf( "DELETE FROM " "poi " "WHERE " "idmd5='%s'" , p->idmd5); res = sql_execute(db, sql, NULL); repaint_all(); } void get_pois() { char sql[256]; char *db; bbox_t bbox; bbox = get_bbox_deg(); db = g_strconcat(foxtrotgps_dir, "/", POI_DB, NULL); if(poi_list) g_slist_free(poi_list); poi_list = NULL; if(global_poi_cat==0) { g_snprintf(sql, 256, "SELECT * FROM poi " "WHERE lat<%f AND lat>%f AND lon>%f AND lon<%f " "LIMIT 1000;", bbox.lat1,bbox.lat2, bbox.lon1, bbox.lon2 ); } else if(global_poi_cat>=1) { g_snprintf(sql, 256, "SELECT * FROM poi " "WHERE cat=%d AND lat<%f AND lat>%f AND lon>%f AND lon<%f " "LIMIT 1000;", global_poi_cat, bbox.lat1,bbox.lat2, bbox.lon1, bbox.lon2 ); } if(poi_list) { g_slist_free(poi_list); poi_list = NULL; } sql_execute(db, sql, sql_cb__poi_get); global_show_pois = TRUE; } void show_poi_detail() { GtkWidget *window, *widget; GtkWidget *label; GSList *list; gchar *buffer = NULL, *buffer2 = NULL; gboolean poi_found = FALSE; float lat, lon,lat_deg,lon_deg; float distance=0; waypoint_t *wp = g_new0(waypoint_t, 1); poi_t *p, *this_poi = NULL; GladeXML *gladexml = glade_xml_new (gladefile, "window5", GETTEXT_PACKAGE); glade_xml_signal_autoconnect (gladexml); window = glade_xml_get_widget (gladexml, "window5"); g_signal_connect_swapped (window, "destroy", G_CALLBACK (g_object_unref), gladexml); lat = pixel2lat(global_zoom, global_y+mouse_y); lon = pixel2lon(global_zoom, global_x+mouse_x); lat_deg = rad2deg(lat); lon_deg = rad2deg(lon); if(gpsdata !=NULL && !global_myposition.lat && !global_myposition.lon) { distance = 6371.0 * acos(sin(deg2rad(gpsdata->fix.latitude)) * sin(lat) + cos(deg2rad(gpsdata->fix.latitude)) * cos(lat) * cos(lon - deg2rad(gpsdata->fix.longitude)) ); } else if(global_myposition.lat && global_myposition.lon) { distance = 6371.0 * acos(sin(deg2rad(global_myposition.lat)) * sin(lat) + cos(deg2rad(global_myposition.lat)) * cos(lat) * cos(lon - deg2rad(global_myposition.lon)) ); } label = lookup_widget(window,"label110"); for(list = poi_list; list != NULL; list = list->next) { p = list->data; if(abs(p->screen_x - mouse_x) < 12 && abs(p->screen_y - mouse_y) < 12 ) { buffer = g_strdup_printf( "%s ", my_strescape_back(p->keywords,NULL)); buffer2 = g_strdup_printf (_("%s\n\nDistance: %.3fkm"), my_strescape_back(p->desc,NULL), distance); poi_found = TRUE; wp->lat = deg2rad(p->lat_deg); wp->lon = deg2rad(p->lon_deg); this_poi = list->data; } } if(!poi_found) buffer = g_strdup (_("No POI found\n")); gtk_label_set_label(GTK_LABEL(label),buffer); label = lookup_widget(window,"label111"); gtk_label_set_label(GTK_LABEL(label), buffer2); widget = lookup_widget(window, "button27"); g_signal_connect ( (gpointer) widget, "clicked", G_CALLBACK (on_button27_clicked), (gpointer) wp); if (this_poi != NULL) { this_poi->widget = window; widget = lookup_widget(window, "button33"); g_signal_connect ( (gpointer) widget, "clicked", G_CALLBACK (on_button33_clicked), (gpointer) this_poi); widget = lookup_widget(window, "button34"); g_signal_connect ( (gpointer) widget, "clicked", G_CALLBACK (on_button34_clicked), (gpointer) this_poi); } gtk_widget_show(window); } gchar * my_strescape_back (const gchar *source, const gchar *exceptions) { const guchar *p; gchar *dest; gchar *q; guchar excmap[256]; g_return_val_if_fail (source != NULL, NULL); p = (guchar *) source; q = dest = g_malloc (strlen (source) * 4 + 1); memset (excmap, 0, 256); if (exceptions) { guchar *e = (guchar *) exceptions; while (*e) { excmap[*e] = 1; e++; } } while (*p) { switch (*p) { case '&': *q++ = '&'; *q++ = 'a'; *q++ = 'm'; *q++ = 'p'; *q++ = ';'; break; default: *q++ = *p; break; } p++; } *q = 0; return dest; }