--- /dev/null
+/*
+ * belltower
+ * an app to find belltowers under Maemo 5
+ *
+ * Copyright (c) 2009 Thomas Thurman <tthurman@gnome.org>
+ * Released under the GPL
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <hildon/hildon.h>
+#include <gtk/gtk.h>
+#include <location/location-gps-device.h>
+#include <dbus/dbus-glib.h>
+
+#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("<b>%s</b>", 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("S<sup>t</sup> %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;
+}