From: Thomas Thurman Date: Thu, 27 Aug 2009 18:44:07 +0000 (-0400) Subject: initial X-Git-Url: http://git.maemo.org/git/?p=belltower;a=commitdiff_plain;h=bc68e335ea0ce064e96bb9c32746d6d460bb8adb initial --- bc68e335ea0ce064e96bb9c32746d6d460bb8adb diff --git a/belltower.c b/belltower.c new file mode 100644 index 0000000..f419364 --- /dev/null +++ b/belltower.c @@ -0,0 +1,573 @@ +/* + * belltower + * an app to find belltowers under Maemo 5 + * + * Copyright (c) 2009 Thomas Thurman + * Released under the GPL + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MAX_FIELDS 50 + +#define EM_DASH "\xE2\x80\x94" + +GtkWidget *window; + +typedef enum { + FieldPrimaryKey, + FieldNationalGrid, + FieldAccRef, + FieldSNLat, + FieldSNLong, + FieldPostcode, + FieldTowerBase, + FieldCounty, + FieldCountry, + FieldDiocese, + FieldPlace, + FieldPlace2, + FieldPlaceCL, + FieldDedication, + FieldBells, + FieldWt, + FieldApp, + FieldNote, + FieldHz, + FieldDetails, + FieldGF, + FieldToilet, + FieldUR, + FieldPDNo, + FieldPracticeNight, + FieldPSt, + FieldPrXF, + FieldOvhaulYr, + FieldContractor, + FieldExtraInfo, + FieldWebPage, + FieldUpdated, + FieldAffiliations, + FieldAltName, + FieldLat, + FieldLong, + FieldSimulator +} field; + +typedef struct { + int serial; + + /* the raw data */ + + char* fields[MAX_FIELDS]; + int n_fields; +} tower; + +static void +show_message (char *message) +{ + HildonNote* note = HILDON_NOTE + (hildon_note_new_information (GTK_WINDOW (window), + message?message: + "Some message was supposed to be here.")); + gtk_dialog_run (GTK_DIALOG (note)); + gtk_widget_destroy (GTK_WIDGET (note)); +} + +static void +call_dbus (DBusBusType type, + char *name, + char *path, + char *interface, + char *method, + char *parameter) +{ + DBusGConnection *connection; + GError *error = NULL; + + DBusGProxy *proxy; + + connection = dbus_g_bus_get (type, + &error); + if (connection == NULL) + { + show_message (error->message); + g_error_free (error); + return; + } + + proxy = dbus_g_proxy_new_for_name (connection, name, path, interface); + + error = NULL; + if (!dbus_g_proxy_call (proxy, method, &error, + G_TYPE_STRING, parameter, + G_TYPE_INVALID, + G_TYPE_INVALID)) + { + show_message (error->message); + g_error_free (error); + } +} + +static void +show_browser (gchar *url) +{ + call_dbus (DBUS_BUS_SESSION, + "com.nokia.osso_browser", + "/com/nokia/osso_browser/request", + "com.nokia.osso_browser", + "load_url", + url); +} + +typedef gboolean (*ParseDoveCallback)(tower *details, gpointer data); +typedef void (*ButtonCallback)(void); + +GtkWidget *tower_window, *buttons, *tower_table; +HildonAppMenu *menu; + +static void +add_table_field (char *name, + char *value) +{ + int row; + GtkLabel *label; + gchar *str; + + g_object_get(tower_table, "n-rows", &row); + + row++; + + gtk_table_resize (GTK_TABLE (tower_table), row, 2); + + label = GTK_LABEL (gtk_label_new (NULL)); + str = g_strdup_printf("%s", name); + gtk_label_set_markup (label, str); + g_free (str); + gtk_label_set_justify (label, GTK_JUSTIFY_RIGHT); + gtk_table_attach_defaults (GTK_TABLE (tower_table), + GTK_WIDGET (label), + 0, 1, row, row+1); + + label = GTK_LABEL (gtk_label_new (value)); + gtk_label_set_justify (label, GTK_JUSTIFY_LEFT); + gtk_table_attach_defaults (GTK_TABLE (tower_table), + GTK_WIDGET (label), + 1, 2, row, row+1); +} + +static void +add_button (char *label, + ButtonCallback callback) +{ + GtkWidget *button; + + button = gtk_button_new_with_label (label); + g_signal_connect (button, "clicked", G_CALLBACK (callback), NULL); + hildon_app_menu_append (menu, GTK_BUTTON (button)); + button = hildon_button_new_with_text (HILDON_SIZE_AUTO_WIDTH | HILDON_SIZE_FINGER_HEIGHT, + HILDON_BUTTON_ARRANGEMENT_VERTICAL, + label, NULL); + g_signal_connect (button, "clicked", G_CALLBACK (callback), NULL); + gtk_box_pack_end (GTK_BOX (buttons), button, FALSE, FALSE, 0); +} + + +static void +bookmark_toggled (GtkButton *button, + gpointer dummy) +{ + show_message ("Bookmarks are not yet implemented."); +} + +char *tower_website = NULL; +char *tower_map = NULL; +char *tower_directions = NULL; +char *peals_list = NULL; + +static void +show_tower_website (void) +{ + show_browser (tower_website); +} + +static void +show_tower_map (void) +{ + show_browser (tower_map); +} + +static void +show_peals_list (void) +{ + show_browser (peals_list); +} + +static gboolean +get_areas_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], + NULL, NULL)) + { + char *display_format; + + 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]); + } + + g_hash_table_insert (hash, + g_strdup(details->fields[FieldCounty]), + display_format); + } + + return TRUE; +} + +static gboolean +single_tower_cb (tower *details, + gpointer data) +{ + + GtkWidget *hbox, *button; + gchar *str; + gint tenor_weight; + gchar *primary_key = (gchar*) data; + + if (strcmp(details->fields[FieldPrimaryKey], primary_key)!=0) + { + /* not this one; keep going */ + return TRUE; + } + + tower_window = hildon_stackable_window_new (); + + if (g_str_has_prefix (details->fields[FieldDedication], + "S ")) + { + /* FIXME: This needs to be cleverer, because we can have + * e.g. "S Peter and S Paul". + * May have to use regexps. + * Reallocation in general even when unchanged is okay, + * because it's the common case (most towers are S Something) + */ + + /* FIXME: Since we're passing this in as markup, + * we need to escape the strings. + */ + + str = g_strdup_printf("St %s, %s", + details->fields[FieldDedication]+2, + details->fields[FieldPlace]); + + } + else + { + str = g_strdup_printf("%s, %s", + details->fields[FieldDedication], + details->fields[FieldPlace]); + } + + hildon_window_set_markup (HILDON_WINDOW (tower_window), + str); + g_free (str); + + hbox = gtk_hbox_new (FALSE, 0); + tower_table = gtk_table_new (0, 2, FALSE); + buttons = gtk_vbox_new (TRUE, 0); + menu = HILDON_APP_MENU (hildon_app_menu_new ()); + + add_table_field ("Postcode", details->fields[FieldPostcode]); + add_table_field ("County", details->fields[FieldCounty]); + add_table_field ("Country", details->fields[FieldCountry]); + add_table_field ("Diocese", details->fields[FieldDiocese]); + add_table_field ("Practice night", details->fields[FieldPracticeNight]); + add_table_field ("Bells", details->fields[FieldBells]); + + tenor_weight = atoi (details->fields[FieldWt]); + str = g_strdup_printf("%dcwt %dqr %dlb in %s", + tenor_weight/112, + (tenor_weight % 112)/28, + tenor_weight % 28, + details->fields[FieldNote] + ); + add_table_field ("Tenor", str); + g_free (str); + + add_button ("Tower website", show_tower_website); + add_button ("Peals", show_peals_list); + add_button ("Map", show_tower_map); + add_button ("Directions", NULL); + + /* don't use a toggle button: it looks stupid */ + button = hildon_button_new_with_text (HILDON_SIZE_AUTO_WIDTH | HILDON_SIZE_FINGER_HEIGHT, + HILDON_BUTTON_ARRANGEMENT_VERTICAL, + "Bookmark", NULL); + g_signal_connect (button, "clicked", G_CALLBACK (bookmark_toggled), NULL); + gtk_box_pack_start (GTK_BOX (buttons), button, FALSE, FALSE, 0); + + gtk_widget_show_all (GTK_WIDGET (menu)); + hildon_window_set_app_menu (HILDON_WINDOW (tower_window), menu); + + gtk_box_pack_end (GTK_BOX (hbox), buttons, TRUE, TRUE, 0); + gtk_box_pack_end (GTK_BOX (hbox), tower_table, TRUE, TRUE, 0); + + gtk_container_add (GTK_CONTAINER (tower_window), hbox); + + g_free (tower_website); + tower_website = g_strdup_printf ("http://%s", details->fields[FieldWebPage]); + g_free (peals_list); + peals_list = g_strdup_printf ("http://www.pealbase.ismysite.co.uk/felstead/tbid.php?tid=%s", + details->fields[FieldTowerBase]); + g_free (tower_map); + tower_map = g_strdup_printf ("http://maps.google.com/maps?q=%s,%s", + details->fields[FieldLat], + details->fields[FieldLong]); + gtk_widget_show_all (GTK_WIDGET (tower_window)); + + return FALSE; +} + +static void +parse_dove (ParseDoveCallback callback, + gpointer data) +{ + FILE *dove = fopen("/usr/share/belltower/dove.txt", "r"); + char tower_rec[4096]; + tower result; + char *i; + gboolean seen_newline; + + if (!dove) + { + show_message ("Cannot open Dove database!"); + exit (255); + } + + result.serial = 0; + + while (fgets (tower_rec, sizeof (tower_rec), dove)) + { + seen_newline = FALSE; + result.fields[0] = tower_rec; + result.n_fields = 0; + for (i=tower_rec; *i; i++) { + if (*i=='\n') + { + seen_newline = TRUE; + } + if (*i=='\\' || *i=='\n') + { + *i = 0; + result.n_fields++; + result.fields[result.n_fields] = i+1; + } + } + + if (!seen_newline) + { + /* keep it simple, stupid */ + show_message ("Line too long, cannot continue."); + exit (255); + } + + if (strcmp (result.fields[FieldCountry], "")==0) + { + result.fields[FieldCountry] = "England"; + } + + if (!callback (&result, data)) + { + fclose (dove); + return; + } + } + + fclose (dove); +} + +static void +nearby_towers (void) +{ + char buffer[4096]; + LocationGPSDevice *device; + device = g_object_new (LOCATION_TYPE_GPS_DEVICE, NULL); + + sprintf(buffer, "%f %f %x", + device->fix->latitude, + device->fix->longitude, + device->fix->fields); + show_message (buffer); + + if (device->fix->fields & LOCATION_GPS_DEVICE_LATLONG_SET) + { + show_message ("I know where you are!"); + } + else + { + show_message ("I don't know where you are!"); + } + + g_object_unref (device); +} + +static void +show_tower (char *primary_key) +{ + parse_dove (single_tower_cb, + primary_key); +} + +static void +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); +} + +static void +towers_by_area (void) +{ + 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); + + GHashTable *hash = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + g_free); + /* + g_free (hash); + */ + + parse_dove (get_areas_cb, + hash); + + g_hash_table_foreach (hash, + put_areas_into_list, + list_store); + + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list_store), + 0, + GTK_SORT_ASCENDING); + + g_object_set (GTK_OBJECT(renderer), "yalign", 0.5, NULL); + g_object_set (GTK_OBJECT(renderer), "xpad", 24, NULL); + + gtk_window_set_title (GTK_WINDOW (dialog), "Towers by area"); + + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview), + 0, "", + renderer, + "text", 0, + NULL); + + gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), + GTK_TREE_MODEL (list_store)); + g_object_unref (list_store); + + hildon_pannable_area_add_with_viewport (HILDON_PANNABLE_AREA (pan), + treeview); + + 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); + + gtk_widget_show_all (GTK_WIDGET (dialog)); + + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (GTK_WIDGET (dialog)); +} + +static void +show_bookmarks (void) +{ + /* nothing */ +} + +static void +tower_search (void) +{ + /* nothing */ +} + +static void +recent_towers (void) +{ + show_tower ("NORTON HE"); +} + +int +main(int argc, char **argv) +{ + GtkWidget *bell, *button, *hbox; + GdkPixbuf *bell_picture; + + gtk_init (&argc, &argv); + g_set_application_name ("Belltower"); + + window = hildon_stackable_window_new (); + gtk_window_set_title (GTK_WINDOW (window), "Belltower"); + + bell_picture = gdk_pixbuf_new_from_file ("/usr/share/belltower/bells1.jpg", NULL); + + buttons = gtk_vbox_new (TRUE, 0); + menu = HILDON_APP_MENU (hildon_app_menu_new ()); + + add_button ("Nearby", nearby_towers); + add_button ("Recent", recent_towers); + add_button ("Bookmarks", show_bookmarks); + add_button ("By area", towers_by_area); + add_button ("Search", tower_search); + + /* extra buttons for the app menu */ + button = gtk_button_new_with_label ("Credits"); + hildon_app_menu_append (menu, GTK_BUTTON (button)); + hildon_app_menu_append (menu, GTK_BUTTON (button)); + + gtk_widget_show_all (GTK_WIDGET (menu)); + hildon_window_set_app_menu (HILDON_WINDOW (window), menu); + + hbox = gtk_hbox_new (FALSE, 0); + gtk_box_pack_end (GTK_BOX (hbox), buttons, TRUE, TRUE, 0); + gtk_box_pack_end (GTK_BOX (hbox), + gtk_image_new_from_pixbuf (bell_picture), + TRUE, TRUE, 0); + + gtk_container_add (GTK_CONTAINER (window), hbox); + gtk_widget_show_all (GTK_WIDGET (window)); + + gtk_main (); + + return EXIT_SUCCESS; +}