X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=belltower.c;h=35031eff4eedefb0ea63b299e1d98ab26d33ba91;hb=c549bd0a53c57953f8928456ba3744880181e76f;hp=f4193649e865b49c2da1930f0602daacdd637422;hpb=bc68e335ea0ce064e96bb9c32746d6d460bb8adb;p=belltower diff --git a/belltower.c b/belltower.c index f419364..35031ef 100644 --- a/belltower.c +++ b/belltower.c @@ -8,19 +8,33 @@ #include #include +#include #include #include #include #include +#include #include #define MAX_FIELDS 50 -#define EM_DASH "\xE2\x80\x94" - GtkWidget *window; typedef enum { + /** stop scanning the database */ + FILTER_STOP, + /** ignore this one */ + FILTER_IGNORE, + /** add this one to the list */ + FILTER_ACCEPT +} FilterResult; + +/* + FIXME: + We should really do this by looking at the header row of the table. + They might decide to put in new columns some day. +*/ +typedef enum { FieldPrimaryKey, FieldNationalGrid, FieldAccRef, @@ -69,6 +83,13 @@ typedef struct { int n_fields; } tower; +/* + * we're going to pretend you're in Helsinki + * until I get the GPS working + */ +double current_lat = 60.161790; +double current_long = 23.924902; + static void show_message (char *message) { @@ -80,6 +101,28 @@ show_message (char *message) gtk_widget_destroy (GTK_WIDGET (note)); } +static gchar* +distance_to_tower (tower *details) +{ + char *endptr; + double tower_lat; + double tower_long; + double km_distance; + const double km_to_miles = 1.609344; + + tower_lat = strtod(details->fields[FieldLat], &endptr); + if (*endptr) return g_strdup ("unknown"); + tower_long = strtod(details->fields[FieldLong], &endptr); + if (*endptr) return g_strdup ("unknown"); + + km_distance = location_distance_between (current_lat, + current_long, + tower_lat, + tower_long); + + return g_strdup_printf("%dmi", (int) (km_distance / km_to_miles)); +} + static void call_dbus (DBusBusType type, char *name, @@ -126,7 +169,7 @@ show_browser (gchar *url) url); } -typedef gboolean (*ParseDoveCallback)(tower *details, gpointer data); +typedef FilterResult (*ParseDoveCallback)(tower *details, gpointer data); typedef void (*ButtonCallback)(void); GtkWidget *tower_window, *buttons, *tower_table; @@ -209,42 +252,79 @@ show_peals_list (void) show_browser (peals_list); } -static gboolean -get_areas_cb (tower *details, - gpointer data) +static FilterResult +get_countries_cb (tower *details, + gpointer data) { GHashTable *hash = (GHashTable *)data; - /* if (details->serial==0) return TRUE; /* header row */ if (!g_hash_table_lookup_extended (hash, - details->fields[FieldCounty], + details->fields[FieldCountry], NULL, NULL)) { - char *display_format; + g_hash_table_insert (hash, + g_strdup(details->fields[FieldCountry]), + g_strdup (details->fields[FieldCountry])); + } - if (strcmp (details->fields[FieldCounty], "")==0) - { - display_format = g_strdup (details->fields[FieldCountry]); - } - else - { - display_format = g_strdup_printf ("%s " EM_DASH " %s", - details->fields[FieldCountry], - details->fields[FieldCounty]); - } + return FILTER_IGNORE; +} - g_hash_table_insert (hash, +typedef struct { + GHashTable *hash; + gchar *country_name; +} country_cb_data; + +typedef struct { + char *country; + char *county; +} country_and_county; + +static FilterResult +get_counties_cb (tower *details, + gpointer data) +{ + country_cb_data *d = (country_cb_data *)data; + + if (details->serial==0) + return FILTER_IGNORE; /* header row */ + + if (strcmp(details->fields[FieldCountry], d->country_name)!=0) + return FILTER_IGNORE; /* wrong country */ + + if (!g_hash_table_lookup_extended (d->hash, + details->fields[FieldCounty], + NULL, NULL)) + { + g_hash_table_insert (d->hash, g_strdup(details->fields[FieldCounty]), - display_format); + g_strdup (details->fields[FieldCounty])); } - return TRUE; + return FILTER_IGNORE; +} + +static FilterResult +get_towers_by_county_cb (tower *details, + gpointer data) +{ + country_and_county *cac = (country_and_county *) data; + + if ((!cac->county || strcmp (cac->county, details->fields[FieldCounty])==0) && + (!cac->country || strcmp (cac->country, details->fields[FieldCountry])==0)) + { + return FILTER_ACCEPT; + } + else + { + return FILTER_IGNORE; + } } -static gboolean +static FilterResult single_tower_cb (tower *details, gpointer data) { @@ -253,11 +333,12 @@ single_tower_cb (tower *details, gchar *str; gint tenor_weight; gchar *primary_key = (gchar*) data; + gchar *miles; if (strcmp(details->fields[FieldPrimaryKey], primary_key)!=0) { /* not this one; keep going */ - return TRUE; + return FILTER_IGNORE; } tower_window = hildon_stackable_window_new (); @@ -297,6 +378,9 @@ single_tower_cb (tower *details, buttons = gtk_vbox_new (TRUE, 0); menu = HILDON_APP_MENU (hildon_app_menu_new ()); + miles = distance_to_tower(details); + + add_table_field ("Distance", miles); add_table_field ("Postcode", details->fields[FieldPostcode]); add_table_field ("County", details->fields[FieldCounty]); add_table_field ("Country", details->fields[FieldCountry]); @@ -304,6 +388,8 @@ single_tower_cb (tower *details, add_table_field ("Practice night", details->fields[FieldPracticeNight]); add_table_field ("Bells", details->fields[FieldBells]); + g_free (miles); + tenor_weight = atoi (details->fields[FieldWt]); str = g_strdup_printf("%dcwt %dqr %dlb in %s", tenor_weight/112, @@ -345,11 +431,50 @@ single_tower_cb (tower *details, details->fields[FieldLong]); gtk_widget_show_all (GTK_WIDGET (tower_window)); - return FALSE; + return FILTER_STOP; +} + +/** + * A tower that was accepted by a filter. + */ +typedef struct { + char *sortkey; + char *primarykey; + char *displayname; +} FoundTower; + +static FoundTower * +found_tower_new (tower *basis) +{ + FoundTower* result = g_new (FoundTower, 1); + gchar *distance = distance_to_tower (basis); + + result->sortkey = g_strdup (basis->fields[FieldPrimaryKey]); + result->primarykey = g_strdup (basis->fields[FieldPrimaryKey]); + result->displayname = g_strdup_printf ("%s, %s (%s, %s) (%s)", + basis->fields[FieldDedication], + basis->fields[FieldPlace], + basis->fields[FieldBells], + basis->fields[FieldPracticeNight], + distance); + + g_free (distance); + + return result; +} + +static void +found_tower_free (FoundTower *tower) +{ + g_free (tower->sortkey); + g_free (tower->primarykey); + g_free (tower->displayname); + g_free (tower); } static void parse_dove (ParseDoveCallback callback, + GSList **filter_results, gpointer data) { FILE *dove = fopen("/usr/share/belltower/dove.txt", "r"); @@ -396,11 +521,25 @@ parse_dove (ParseDoveCallback callback, result.fields[FieldCountry] = "England"; } - if (!callback (&result, data)) + switch (callback (&result, data)) { + case FILTER_IGNORE: + /* nothing */ + break; + + case FILTER_STOP: fclose (dove); return; + + case FILTER_ACCEPT: + if (filter_results) + { + *filter_results = g_slist_append (*filter_results, + found_tower_new (&result)); + } } + + result.serial++; } fclose (dove); @@ -434,8 +573,78 @@ nearby_towers (void) static void show_tower (char *primary_key) { - parse_dove (single_tower_cb, - primary_key); + parse_dove (single_tower_cb, NULL, primary_key); +} + +static void +show_towers_from_list (GSList *list) +{ + GtkWidget *dialog; + GtkWidget *selector; + gint result = -1; + GSList *cursor; + gchar foo[2048]; + + if (!list) + { + hildon_banner_show_information(window, + NULL, + "No towers found."); + return; + } + + if (!list->next) + { + /* only one; don't bother showing the list */ + hildon_banner_show_information(window, + NULL, + "One tower found."); + show_tower (list->data); + + /* FIXME: and free the list */ + return; + } + + dialog = hildon_picker_dialog_new (GTK_WINDOW (window)); + selector = hildon_touch_selector_new_text (); + + for (cursor=list; cursor; cursor=cursor->next) + { + FoundTower* found = (FoundTower*) cursor->data; + hildon_touch_selector_append_text (HILDON_TOUCH_SELECTOR (selector), + found->displayname); + } + + hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), + HILDON_TOUCH_SELECTOR (selector)); + + gtk_widget_show_all (GTK_WIDGET (dialog)); + + if (gtk_dialog_run (GTK_DIALOG (dialog))==GTK_RESPONSE_OK) + { + GList *rows = hildon_touch_selector_get_selected_rows (HILDON_TOUCH_SELECTOR (selector), + 0); + GtkTreePath *path = (GtkTreePath*) rows->data; + gint *indices = gtk_tree_path_get_indices (path); + + result = *indices; + } + + gtk_widget_destroy (GTK_WIDGET (dialog)); + + if (result!=-1) + { + FoundTower *found = (FoundTower *) g_slist_nth_data (list, result); + show_tower (found->primarykey); + } + + /* FIXME: and free the list */ +} + +static gint strcmp_f (gconstpointer a, + gconstpointer b) +{ + return strcmp ((char*)a, (char*)b); } static void @@ -443,88 +652,120 @@ put_areas_into_list (gpointer key, gpointer value, gpointer data) { - GtkTreeIter iter; - GtkListStore *list_store = (GtkListStore*) data; - gtk_list_store_append (list_store, &iter); - gtk_list_store_set (list_store, &iter, - 0, value, - -1); + GSList **list = (GSList **)data; + *list = g_slist_insert_sorted (*list, + value, + strcmp_f); } static void -towers_by_area (void) +towers_by_subarea (gchar *area) { - GtkWidget *dialog = gtk_dialog_new (); - GtkWidget *vbox = GTK_DIALOG(dialog)->vbox; - GtkCellRenderer *renderer = gtk_cell_renderer_text_new (); - GtkWidget *treeview = hildon_gtk_tree_view_new (HILDON_UI_MODE_NORMAL); - GtkWidget *pan = hildon_pannable_area_new (); - GtkListStore *list_store = gtk_list_store_new(1, G_TYPE_STRING); - + GtkWidget *dialog = hildon_picker_dialog_new (GTK_WINDOW (window)); + GtkWidget *selector = hildon_touch_selector_new_text (); GHashTable *hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); - /* - g_free (hash); - */ + GSList *list=NULL, *cursor; + gchar *title = g_strdup_printf ("Areas of %s", area); + country_cb_data d = { hash, area }; + country_and_county cac = { area, NULL }; + + gtk_window_set_title (GTK_WINDOW (dialog), title); + g_free (title); - parse_dove (get_areas_cb, - hash); + parse_dove (get_counties_cb, NULL, &d); g_hash_table_foreach (hash, put_areas_into_list, - list_store); + &list); + + for (cursor=list; cursor; cursor=cursor->next) + { + hildon_touch_selector_append_text (HILDON_TOUCH_SELECTOR (selector), + cursor->data); + } + + hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), + HILDON_TOUCH_SELECTOR (selector)); - gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list_store), - 0, - GTK_SORT_ASCENDING); + gtk_widget_show_all (GTK_WIDGET (dialog)); - g_object_set (GTK_OBJECT(renderer), "yalign", 0.5, NULL); - g_object_set (GTK_OBJECT(renderer), "xpad", 24, NULL); + if (gtk_dialog_run (GTK_DIALOG (dialog))==GTK_RESPONSE_OK) + { + GSList *matches = NULL; + cac.county = strdup (hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector))); + + parse_dove (get_towers_by_county_cb, + &matches, + &cac); + g_free (cac.county); + + show_towers_from_list (matches); + } + g_hash_table_unref (hash); + gtk_widget_destroy (GTK_WIDGET (dialog)); +} + +static void +towers_by_area (void) +{ + GtkWidget *dialog = hildon_picker_dialog_new (GTK_WINDOW (window)); + GtkWidget *selector = hildon_touch_selector_new_text (); + GHashTable *hash = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + g_free); + GSList *list = NULL, *cursor; + gchar *result = NULL; - gtk_window_set_title (GTK_WINDOW (dialog), "Towers by area"); + gtk_window_set_title (GTK_WINDOW (dialog), "Areas of the world"); - gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview), - 0, "", - renderer, - "text", 0, - NULL); + parse_dove (get_countries_cb, NULL, hash); - gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), - GTK_TREE_MODEL (list_store)); - g_object_unref (list_store); + g_hash_table_foreach (hash, + put_areas_into_list, + &list); - hildon_pannable_area_add_with_viewport (HILDON_PANNABLE_AREA (pan), - treeview); + for (cursor=list; cursor; cursor=cursor->next) + { + hildon_touch_selector_append_text (HILDON_TOUCH_SELECTOR (selector), + cursor->data); + } - gtk_widget_set_size_request (treeview, 480, 800); - hildon_pannable_area_set_size_request_policy (HILDON_PANNABLE_AREA (pan), - HILDON_SIZE_REQUEST_CHILDREN); - gtk_container_add(GTK_CONTAINER (vbox), pan); + hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), + HILDON_TOUCH_SELECTOR (selector)); gtk_widget_show_all (GTK_WIDGET (dialog)); - gtk_dialog_run (GTK_DIALOG (dialog)); + if (gtk_dialog_run (GTK_DIALOG (dialog))==GTK_RESPONSE_OK) + { + result = g_strdup (hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector))); + } + g_hash_table_unref (hash); gtk_widget_destroy (GTK_WIDGET (dialog)); + + if (result) + { + towers_by_subarea (result); + g_free (result); + } } static void show_bookmarks (void) { - /* nothing */ } static void tower_search (void) { - /* nothing */ } static void recent_towers (void) { - show_tower ("NORTON HE"); } int @@ -538,6 +779,7 @@ main(int argc, char **argv) window = hildon_stackable_window_new (); gtk_window_set_title (GTK_WINDOW (window), "Belltower"); + g_signal_connect (G_OBJECT (window), "delete_event", G_CALLBACK (gtk_main_quit), NULL); bell_picture = gdk_pixbuf_new_from_file ("/usr/share/belltower/bells1.jpg", NULL);