Index: src/types.h =================================================================== --- src/types.h (revision 12) +++ src/types.h (revision 13) @@ -443,8 +443,16 @@ GCond *cond; }; +typedef struct _Tile Tile; +struct _Tile +{ + gint x, y; + gint8 z; +}; + /** Data used during the asynchronous progress update phase of automatic map * downloading. */ +/* TODO: merge with Tile */ typedef struct _MapUpdateTask MapUpdateTask; struct _MapUpdateTask { Index: src/maps.c =================================================================== --- src/maps.c (revision 12) +++ src/maps.c (revision 13) @@ -58,6 +58,7 @@ #include "display.h" #include "main.h" #include "maps.h" +#include "poi.h" #include "menu.h" #include "settings.h" #include "util.h" @@ -119,6 +120,7 @@ GtkWidget *dialog; GtkWidget *notebook; GtkWidget *tbl_area; + GtkWidget *tbl_pois; /* The "Setup" tab. */ GtkWidget *rad_download; @@ -126,6 +128,7 @@ GtkWidget *chk_overwrite; GtkWidget *rad_by_area; GtkWidget *rad_by_route; + GtkWidget *rad_by_pois; GtkWidget *num_route_radius; /* The "Area" tab. */ @@ -190,6 +193,12 @@ static MapCache _map_cache; +typedef struct _MapmanData MapmanData; +struct _MapmanData { + MapUpdateType update_type; + gint download_batch_id; +}; + const gchar* layer_timestamp_key = "tEXt::mm_ts"; @@ -2934,9 +2943,10 @@ static gboolean mapman_by_area(gdouble start_lat, gdouble start_lon, gdouble end_lat, gdouble end_lon, MapmanInfo *mapman_info, - MapUpdateType update_type, - gint download_batch_id) + MapmanData *mapman_data) { + MapUpdateType update_type = mapman_data->update_type; + gint download_batch_id = mapman_data->download_batch_id; gint start_unitx, start_unity, end_unitx, end_unity; gint num_maps = 0; gint z; @@ -3045,9 +3055,10 @@ } static gboolean -mapman_by_route(MapmanInfo *mapman_info, MapUpdateType update_type, - gint download_batch_id) +mapman_by_route(MapmanInfo *mapman_info, MapmanData *mapman_data) { + MapUpdateType update_type = mapman_data->update_type; + gint download_batch_id = mapman_data->download_batch_id; GtkWidget *confirm; gint prev_tilex, prev_tiley, num_maps = 0, z; Point *curr; @@ -3175,6 +3186,170 @@ } static void +poi_hash_destroy_key_val(gpointer data) +{ + g_free(data); +} + +static void +mapman_cat_poi_tiles_dl(gpointer key_raw, gpointer val_raw, gpointer data) +{ + Tile *tile = val_raw; + MapmanData *mm = data; + + /* Make sure this tile is even possible. */ + if((unsigned)tile->x < unit2ztile(WORLD_SIZE_UNITS, tile->z) + && (unsigned)tile->y < unit2ztile(WORLD_SIZE_UNITS, tile->z)) + { + RepoData* rd = _curr_repo; + while(rd) { + if (rd == _curr_repo || (rd->layer_enabled && MAPDB_EXISTS(rd))) + { + mapdb_initiate_update(rd, tile->z, tile->x, tile->y, + mm->update_type, mm->download_batch_id, + (abs(tile->x - unit2tile(_next_center.unitx)) + + abs(tile->y - unit2tile(_next_center.unity))), + NULL); + } + rd = rd->layers; + } + } +} + +static gboolean +mapman_by_pois(MapmanInfo *mapman_info, GtkListStore *poi_store, + MapmanData *mapman_data) +{ + gint num_maps; + GtkWidget *confirm; + gchar buffer[80]; + GSList *list_iter; + GtkTreeIter tree_iter; + GHashTable *tiles; + + vprintf("%s()\n", __PRETTY_FUNCTION__); + + if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(poi_store), &tree_iter)) + return FALSE; + + tiles = g_hash_table_new_full(g_str_hash, g_str_equal, + poi_hash_destroy_key_val, poi_hash_destroy_key_val); + + do + { + GSList *poi_list; + gchar key[256]; + gint id; + gboolean selected; + gtk_tree_model_get(GTK_TREE_MODEL(poi_store), &tree_iter, + CAT_ID, &id, + CAT_ENABLED, &selected, + -1); + + if(!selected) + continue; + + poi_list = get_category_pois(id); + for(list_iter = poi_list; list_iter; list_iter = list_iter->next) + { + PoiInfo *poi = list_iter->data; + gint unit_start_x, unit_start_y, unit_end_x, unit_end_y; + int r; + int z; + + /* TODO: radius (in metres) */ + latlon2unit(poi->lat, poi->lon, unit_start_x, unit_start_y); + latlon2unit(poi->lat, poi->lon, unit_end_x, unit_end_y); + + for(z = 0; z <= MAX_ZOOM; ++z) + { + gint start_tile_x, end_tile_x; + gint start_tile_y, end_tile_y; + gint x, y; + + if(!gtk_toggle_button_get_active( + GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z]))) + continue; + + start_tile_x = unit2ztile(unit_start_x, z); + end_tile_x = unit2ztile(unit_end_x, z); + start_tile_y = unit2ztile(unit_start_y, z); + end_tile_y = unit2ztile(unit_end_y, z); + + if(start_tile_x > end_tile_x) + { + gint t = start_tile_x; + start_tile_x = end_tile_x; + end_tile_x = t; + } + if(start_tile_y > end_tile_y) + { + gint t = start_tile_y; + start_tile_y = end_tile_y; + end_tile_y = t; + } + + for(y = start_tile_y; y <= end_tile_y; y++) + { + for(x = start_tile_x; x <= end_tile_x; x++) + { + snprintf(key, 255, "%d,%d,%d", x, y, z); + if(!g_hash_table_lookup(tiles, key)) + { + Tile *tile = g_new0(Tile, 1); + tile->x = x; + tile->y = y; + tile->z = z; + g_hash_table_replace(tiles, g_strdup(key), tile); + } + } + } + } + } + for(list_iter = poi_list; list_iter; list_iter = list_iter->next) + g_free(list_iter->data); + if (poi_list) + g_slist_free(poi_list); + } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(poi_store), &tree_iter)); + + num_maps = g_hash_table_size(tiles); + /* TODO what is num_maps is zero */ + + if(mapman_data->update_type == MAP_UPDATE_DELETE) + { + snprintf(buffer, sizeof(buffer), "%s %d %s", _("Confirm DELETION of"), + num_maps, _("maps ")); + } + else + { + snprintf(buffer, sizeof(buffer), + "%s %d %s\n(%s %.2f MB)\n", _("Confirm download of"), + num_maps, _("maps"), _("up to about"), + num_maps * (strstr(_curr_repo->url, "%s") ? 18e-3 : 6e-3)); + } + confirm = hildon_note_new_confirmation( + GTK_WINDOW(mapman_info->dialog), buffer); + + if(GTK_RESPONSE_OK != gtk_dialog_run(GTK_DIALOG(confirm))) + { + g_hash_table_destroy(tiles); + gtk_widget_destroy(confirm); + vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__); + return FALSE; + } + + g_mutex_lock(_mut_priority_mutex); + g_hash_table_foreach(tiles, mapman_cat_poi_tiles_dl, mapman_data); + g_mutex_unlock(_mut_priority_mutex); + + g_hash_table_destroy(tiles); + gtk_widget_destroy(confirm); + vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__); + return TRUE; +} + + +static void mapman_clear(GtkWidget *widget, MapmanInfo *mapman_info) { gint z; @@ -3202,18 +3377,82 @@ gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(mapman_info->rad_download))); + gtk_widget_hide(mapman_info->tbl_area); + gtk_widget_hide(mapman_info->tbl_pois); + gtk_widget_set_sensitive(mapman_info->num_route_radius, + gtk_toggle_button_get_active( + GTK_TOGGLE_BUTTON(mapman_info->rad_by_route))); + if(gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(mapman_info->rad_by_area))) gtk_widget_show(mapman_info->tbl_area); - else if(gtk_notebook_get_n_pages(GTK_NOTEBOOK(mapman_info->notebook)) == 3) - gtk_widget_hide(mapman_info->tbl_area); + else if(gtk_toggle_button_get_active( + GTK_TOGGLE_BUTTON(mapman_info->rad_by_pois))) + gtk_widget_show(mapman_info->tbl_pois); + vprintf("%s(): return\n", __PRETTY_FUNCTION__); +} - gtk_widget_set_sensitive(mapman_info->num_route_radius, - gtk_toggle_button_get_active( - GTK_TOGGLE_BUTTON(mapman_info->rad_by_route))); +static void +category_toggled(GtkCellRendererToggle *cell, gchar *path, GtkListStore *data) +{ + GtkTreeIter iter; + gboolean cat_enabled; + printf("%s()\n", __PRETTY_FUNCTION__); + + GtkTreeModel *model = GTK_TREE_MODEL(data); + if( !gtk_tree_model_get_iter_from_string(model, &iter, path) ) + return; + + gtk_tree_model_get(model, &iter, + CAT_ENABLED, &cat_enabled, + -1); + + gtk_list_store_set(GTK_LIST_STORE(model), &iter, + CAT_ENABLED, cat_enabled ^ 1, -1); + vprintf("%s(): return\n", __PRETTY_FUNCTION__); } +static GtkWidget * +mapman_create_poi_page(GtkListStore **store) +{ + GtkTreeViewColumn *column; + GtkWidget *tree_view; + GtkCellRenderer *renderer; + GtkWidget *sw; + + *store = poi_create_poi_store(); + tree_view = gtk_tree_view_new(); + + gtk_tree_selection_set_mode( + gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)), + GTK_SELECTION_SINGLE); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_view), TRUE); + + renderer = gtk_cell_renderer_toggle_new(); + column = gtk_tree_view_column_new_with_attributes( + _("Enabled"), renderer, "active", CAT_ENABLED, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column); + g_signal_connect(renderer, "toggled", + G_CALLBACK(category_toggled), *store); + + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes( + _("Label"), renderer, "text", CAT_LABEL, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column); + + gtk_tree_view_set_model(GTK_TREE_VIEW(tree_view), GTK_TREE_MODEL(*store)); + g_object_unref(*store); + + sw = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), + GTK_POLICY_NEVER, + GTK_POLICY_AUTOMATIC); + gtk_container_add(GTK_CONTAINER(sw), tree_view); + + return sw; +} + gboolean mapman_dialog() { @@ -3227,6 +3466,7 @@ GtkWidget *lbl_gps_lon; GtkWidget *lbl_center_lat; GtkWidget *lbl_center_lon; + GtkListStore *poi_store; MapmanInfo mapman_info; gchar buffer[80]; @@ -3351,12 +3591,18 @@ _("By Area (see tab)")), FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), + mapman_info.rad_by_pois + = gtk_radio_button_new_with_label_from_widget( + GTK_RADIO_BUTTON(mapman_info.rad_by_area), + _("Around POIs (see tab)")), + FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox = gtk_hbox_new(FALSE, 4), FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), mapman_info.rad_by_route = gtk_radio_button_new_with_label_from_widget( - GTK_RADIO_BUTTON(mapman_info.rad_by_area), + GTK_RADIO_BUTTON(mapman_info.rad_by_pois), _("Along Route - Radius (tiles):")), FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), @@ -3550,6 +3796,12 @@ #endif } + + /* POIs page. */ + /* TODO: list categories for POI page on demand */ + gtk_notebook_append_page(GTK_NOTEBOOK(mapman_info.notebook), + mapman_info.tbl_pois = mapman_create_poi_page(&poi_store), + label = gtk_label_new(_("POIs"))); /* Default action is to download by area. */ gtk_toggle_button_set_active( @@ -3563,6 +3815,8 @@ G_CALLBACK(mapman_update_state), &mapman_info); g_signal_connect(G_OBJECT(mapman_info.rad_by_route), "clicked", G_CALLBACK(mapman_update_state), &mapman_info); + g_signal_connect(G_OBJECT(mapman_info.rad_by_pois), "clicked", + G_CALLBACK(mapman_update_state), &mapman_info); /* Initialize fields. Do no use g_ascii_formatd; these strings will be * output (and parsed) as locale-dependent. */ @@ -3634,25 +3888,32 @@ while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog))) { - MapUpdateType update_type; static gint8 download_batch_id = INT8_MIN; + MapmanData mapman_data; if(gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(mapman_info.rad_delete))) - update_type = MAP_UPDATE_DELETE; + mapman_data.update_type = MAP_UPDATE_DELETE; else if(gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(mapman_info.chk_overwrite))) - update_type = MAP_UPDATE_OVERWRITE; + mapman_data.update_type = MAP_UPDATE_OVERWRITE; else - update_type = MAP_UPDATE_ADD; + mapman_data.update_type = MAP_UPDATE_ADD; ++download_batch_id; + mapman_data.download_batch_id = download_batch_id; if(gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(mapman_info.rad_by_route))) { - if(mapman_by_route(&mapman_info, update_type, download_batch_id)) + if(mapman_by_route(&mapman_info, &mapman_data)) break; } + else if(gtk_toggle_button_get_active( + GTK_TOGGLE_BUTTON(mapman_info.rad_by_pois))) + { + if(mapman_by_pois(&mapman_info, poi_store, &mapman_data)) + break; + } else { const gchar *text_lon, *text_lat; @@ -3680,7 +3941,7 @@ if(mapman_by_area(start_lat, start_lon, end_lat, end_lon, - &mapman_info, update_type, download_batch_id)) + &mapman_info, &mapman_data)) break; } } Index: src/poi.c =================================================================== --- src/poi.c (revision 12) +++ src/poi.c (revision 13) @@ -63,6 +63,7 @@ static sqlite3_stmt *_stmt_browsecat_poi = NULL; static sqlite3_stmt *_stmt_select_poi = NULL; static sqlite3_stmt *_stmt_select_nearest_poi = NULL; +static sqlite3_stmt *_stmt_select_cat_poi = NULL; static sqlite3_stmt *_stmt_insert_poi = NULL; static sqlite3_stmt *_stmt_update_poi = NULL; static sqlite3_stmt *_stmt_delete_poi = NULL; @@ -269,6 +270,14 @@ "+ ($LON - p.lon) * ($LON - p.lon)) limit 1", -1, &_stmt_select_nearest_poi, NULL); + /* select lat/lon for all pois in category*/ + sqlite3_prepare(_poi_db, + "select p.lat, p.lon" + " from poi p inner join category c" + " on p.cat_id = c.cat_id" + " where c.cat_id = ?", + -1, &_stmt_select_cat_poi, NULL); + /* insert poi */ sqlite3_prepare(_poi_db, "insert into poi (lat, lon, label, desc, cat_id)" @@ -383,6 +392,30 @@ *id = poi->poi_id; } +GSList * +get_category_pois(gint cat) +{ + GSList *list = NULL; + printf("%s(%d, %d)\n", __PRETTY_FUNCTION__); + + if(SQLITE_OK != sqlite3_bind_double(_stmt_select_cat_poi, 1, cat)) + { + g_printerr("Failed to bind values for _stmt_select_cat_poi\n"); + return NULL; + } + + while(SQLITE_ROW == sqlite3_step(_stmt_select_cat_poi)) + { + PoiInfo *poi = g_new0(PoiInfo, 1); + poi->lat = sqlite3_column_double(_stmt_select_cat_poi, 0); + poi->lon = sqlite3_column_double(_stmt_select_cat_poi, 1); + list = g_slist_append(list, poi); + } + sqlite3_reset(_stmt_select_cat_poi); + vprintf("%s(): return\n", __PRETTY_FUNCTION__); + return list; +} + gboolean select_poi(gint unitx, gint unity, PoiInfo *poi, gboolean quick) { @@ -879,6 +912,37 @@ return store; } +GtkListStore * +poi_create_poi_store() +{ + GtkTreeIter iter; + GtkListStore *store; + printf("%s()\n", __PRETTY_FUNCTION__); + + store = gtk_list_store_new(CAT_NUM_COLUMNS, + G_TYPE_UINT, + G_TYPE_BOOLEAN, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_UINT); + + while(SQLITE_ROW == sqlite3_step(_stmt_selall_cat)) + { + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, + CAT_ID, sqlite3_column_int(_stmt_selall_cat, 0), + CAT_ENABLED, sqlite3_column_int(_stmt_selall_cat, 3), + CAT_LABEL, sqlite3_column_text(_stmt_selall_cat, 1), + CAT_DESC, sqlite3_column_text(_stmt_selall_cat, 2), + CAT_POI_CNT, sqlite3_column_int(_stmt_selall_cat, 4), + -1); + } + sqlite3_reset(_stmt_selall_cat); + + vprintf("%s(): return %p\n", __PRETTY_FUNCTION__, store); + return store; +} + static gboolean category_add(GtkWidget *widget, PoiCategoryEditInfo *pcedit) { Index: src/poi.h =================================================================== --- src/poi.h (revision 12) +++ src/poi.h (revision 13) @@ -30,6 +30,8 @@ gboolean select_poi(gint unitx, gint unity, PoiInfo *poi, gboolean quick); +GSList *get_category_pois(gint cat); + gboolean category_list_dialog(GtkWidget *parent); gboolean poi_dialog(GtkWidget *parent, PoiInfo *poi, gboolean is_add_dialog); @@ -39,6 +41,8 @@ gint poi_get_next_id(); +GtkListStore *poi_create_poi_store(); + void map_render_poi(void); void poi_destroy(void);