initial
authorThomas Thurman <tthurman@gnome.org>
Thu, 27 Aug 2009 18:44:07 +0000 (14:44 -0400)
committerThomas Thurman <tthurman@gnome.org>
Thu, 27 Aug 2009 18:44:07 +0000 (14:44 -0400)
belltower.c [new file with mode: 0644]

diff --git a/belltower.c b/belltower.c
new file mode 100644 (file)
index 0000000..f419364
--- /dev/null
@@ -0,0 +1,573 @@
+/*
+ * 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;
+}