#define MAX_FIELDS 50
#define MAX_RECENT 5
#define CONFIG_GENERAL_GROUP "General"
+#define CONFIG_DISTANCES_KEY "Distances"
+#define CONFIG_TOWERSORT_KEY "Towersort"
#define CONFIG_BOOKMARK_GROUP "Bookmarks"
#define CONFIG_RECENT_GROUP "Recent"
#define CONFIG_SEEN_CREDITS_KEY "seen_credits"
*/
#define MANY_BELLTOWERS 10
+char *distances_settings[] = {
+ CONFIG_DISTANCES_KEY,
+ "Distances are measured in...",
+ "Miles",
+ "Kilometres",
+ NULL
+};
+
+char *towersort_settings[] = {
+ CONFIG_TOWERSORT_KEY,
+ "Towers are sorted by...",
+ "Name of town",
+ "Distance from you",
+ "Days until practice night",
+ "Number of bells",
+ "Weight of tenor",
+ NULL
+};
+
+char **settings[] = {
+ distances_settings,
+ towersort_settings
+};
+
+gint settings_value[G_N_ELEMENTS (settings)] = { 0, };
+
+typedef enum {
+ SETTINGS_DISTANCES,
+ SETTINGS_TOWERSORT
+} Settings;
+
+typedef enum {
+ DISTANCES_MILES,
+ DISTANCES_KILOMETRES
+} DistancesSetting;
+
+typedef enum {
+ TOWERSORT_TOWN,
+ TOWERSORT_DISTANCE,
+ TOWERSORT_PRACTICE,
+ TOWERSORT_BELLS,
+ TOWERSORT_WEIGHT
+} TowersortSetting;
+
GtkWidget *window;
LocationGPSDevice *device;
GKeyFile *static_content;
static void
load_config (void)
{
+ gint i;
+
static_content = g_key_file_new ();
if (!g_key_file_load_from_file (static_content,
CONFIG_FILENAME,
G_KEY_FILE_KEEP_COMMENTS,
NULL);
+
+ for (i=0; i<G_N_ELEMENTS (settings); i++)
+ {
+ gchar *value = g_key_file_get_string (config,
+ CONFIG_GENERAL_GROUP,
+ settings[i][0],
+ NULL);
+
+ settings_value[i] = 0;
+
+ if (value)
+ {
+ gint j=0;
+ char **cursor = settings[i]+2;
+
+ while (*cursor)
+ {
+ if (strcmp (value, *cursor)==0)
+ {
+ settings_value[i] = j;
+ break;
+ }
+ cursor++;
+ j++;
+ }
+ }
+ }
}
/**
device->fix->longitude,
tower_lat,
tower_long);
-
- return (int) (km_distance / km_to_miles);
+ if (settings_value[SETTINGS_DISTANCES]==DISTANCES_KILOMETRES)
+ return (int) km_distance;
+ else
+ return (int) (km_distance / km_to_miles);
}
static gchar*
distance_to_tower_str (tower *details)
{
- int miles = distance_to_tower (details);
+ int distance = distance_to_tower (details);
- if (miles==-1)
+ if (distance==-1)
{
return g_strdup ("unknown");
}
+ else if (settings_value[SETTINGS_DISTANCES]==DISTANCES_KILOMETRES)
+ {
+ return g_strdup_printf("%dkm", (int) distance);
+ }
else
{
- return g_strdup_printf("%dmi", (int) miles);
+ return g_strdup_printf("%dmi", (int) distance);
}
}
+/**
+ * Returns the number of days from today until
+ * the tower's practice night. If the tower's
+ * practice night is unknown, returns 9: this
+ * means that such towers always sort to the end.
+ */
+static gint
+days_until_practice_night (tower *details)
+{
+ /* let's not use the date parsing routines, because
+ * we might get confused by locales, and the day names
+ * used in Dove are constant
+ */
+ time_t now = time (NULL);
+ struct tm *calendar = localtime (&now);
+ const char* dove_days = "SunMonTueWedThuFriSat";
+ char *found;
+ gint practice_night;
+
+ if (strcmp (details->fields[FieldPracticeNight], "")==0)
+ {
+ /* we don't know */
+ return 9;
+ }
+
+ found = strstr (dove_days, details->fields[FieldPracticeNight]);
+
+ if (!found)
+ {
+ return 9;
+ }
+
+ practice_night = (found-dove_days)/3;
+
+ return ((practice_night+7)-calendar->tm_wday)%7;
+}
+
static void
call_dbus (DBusBusType type,
char *name,
static FilterResult
get_nearby_towers_cb (tower *details,
- gpointer data)
+ gpointer distance)
{
if (details->serial==0)
return FILTER_IGNORE; /* header row */
- if (distance_to_tower (details) < 50)
+ if (distance_to_tower (details) <= GPOINTER_TO_INT (distance))
{
return FILTER_ACCEPT;
}
gchar *str;
gint tenor_weight;
gchar *primary_key = (gchar*) data;
- gchar *miles;
+ gchar *distance;
if (strcmp(details->fields[FieldPrimaryKey], primary_key)!=0)
{
buttons = gtk_vbox_new (TRUE, 0);
menu = HILDON_APP_MENU (hildon_app_menu_new ());
- miles = distance_to_tower_str(details);
+ distance = distance_to_tower_str(details);
- add_table_field ("Distance", miles);
+ add_table_field ("Distance", distance);
add_table_field ("Postcode", details->fields[FieldPostcode]);
add_table_field ("County", details->fields[FieldCounty]);
add_table_field ("Country", details->fields[FieldCountry]);
add_table_field ("Practice night", details->fields[FieldPracticeNight]);
add_table_field ("Bells", details->fields[FieldBells]);
- g_free (miles);
+ g_free (distance);
tenor_weight = atoi (details->fields[FieldWt]);
str = g_strdup_printf("%dcwt %dqr %dlb in %s",
{
FoundTower* result = g_new (FoundTower, 1);
- result->sortkey = g_strdup (basis->fields[FieldPrimaryKey]);
+ switch (settings_value[SETTINGS_TOWERSORT])
+ {
+ case TOWERSORT_DISTANCE:
+ result->sortkey = g_strdup_printf ("%5d %s",
+ distance_to_tower (basis),
+ basis->fields[FieldPlace]);
+ break;
+ case TOWERSORT_PRACTICE:
+ result->sortkey = g_strdup_printf ("%d %s",
+ days_until_practice_night (basis),
+ basis->fields[FieldPlace]);
+ break;
+ case TOWERSORT_BELLS:
+ result->sortkey = g_strdup_printf ("%10s", basis->fields[FieldBells]);
+ break;
+ case TOWERSORT_WEIGHT:
+ result->sortkey = g_strdup_printf ("%10s", basis->fields[FieldWt]);
+ break;
+ case TOWERSORT_TOWN:
+ default:
+ result->sortkey = g_strdup (basis->fields[FieldPlace]);
+ }
+
result->primarykey = g_strdup (basis->fields[FieldPrimaryKey]);
if (device->fix->fields & LOCATION_GPS_DEVICE_LATLONG_SET)
}
/**
+ * Comparison function for FoundTower objects.
+ *
+ * \param a a FoundTower
+ * \param b another FoundTower
+ */
+gint found_tower_compare (gconstpointer a,
+ gconstpointer b)
+{
+ FoundTower *fta = (FoundTower *)a;
+ FoundTower *ftb = (FoundTower *)b;
+
+ return strcmp (fta->sortkey, ftb->sortkey);
+}
+
+/**
* Calls a given function once for each tower in the world.
* (The first call, however, is a header row.)
*
return;
case FILTER_ACCEPT:
- filter_results = g_slist_append (filter_results,
- found_tower_new (&result));
+ filter_results = g_slist_insert_sorted (filter_results,
+ found_tower_new (&result),
+ found_tower_compare);
}
result.serial++;
}
parse_dove (get_nearby_towers_cb,
- NULL,
+ settings_value[SETTINGS_DISTANCES]==DISTANCES_KILOMETRES?
+ GINT_TO_POINTER (80) :
+ GINT_TO_POINTER (50),
+ settings_value[SETTINGS_DISTANCES]==DISTANCES_KILOMETRES?
+ "Towers within eighty kilometres of you":
"Towers within fifty miles of you");
}
save_config ();
}
+static void
+settings_dialogue (void)
+{
+ GtkWidget *dialog, *button;
+ GtkWidget *selector[G_N_ELEMENTS (settings)];
+ gint i;
+
+ dialog = gtk_dialog_new_with_buttons ("Settings",
+ GTK_WINDOW (window),
+ GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
+ NULL
+ );
+
+ for (i=0; i<G_N_ELEMENTS (settings); i++)
+ {
+ char **cursor = settings[i]+2;
+ selector[i] = hildon_touch_selector_new_text ();
+
+ while (*cursor)
+ {
+ hildon_touch_selector_append_text (HILDON_TOUCH_SELECTOR (selector[i]), *cursor);
+ cursor++;
+ }
+
+ hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector[i]), 0, settings_value[i]);
+
+ button = hildon_picker_button_new (HILDON_SIZE_AUTO, HILDON_BUTTON_ARRANGEMENT_VERTICAL);
+ hildon_button_set_title (HILDON_BUTTON (button), settings[i][1]);
+ hildon_picker_button_set_selector (HILDON_PICKER_BUTTON (button),
+ HILDON_TOUCH_SELECTOR (selector[i]));
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
+ button,
+ TRUE, TRUE, 0);
+ }
+
+ gtk_widget_show_all (GTK_WIDGET (GTK_DIALOG(dialog)->vbox));
+ gtk_dialog_run (GTK_DIALOG (dialog));
+
+ for (i=0; i<G_N_ELEMENTS (settings); i++)
+ {
+ GList *rows = hildon_touch_selector_get_selected_rows (HILDON_TOUCH_SELECTOR (selector[i]),
+ 0);
+ GtkTreePath *path = (GtkTreePath*) rows->data;
+ gint *indices = gtk_tree_path_get_indices (path);
+
+ g_key_file_set_string (config,
+ CONFIG_GENERAL_GROUP,
+ settings[i][0],
+ hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector[i])));
+
+ settings_value[i] = *indices;
+ }
+ save_config ();
+
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
int
main(int argc, char **argv)
{
add_button ("Bookmarks", show_bookmarks);
add_button ("By area", towers_by_area);
add_button ("Search", tower_search);
+ /* This won't be a button on the main screen
+ * for always, but we'll put it there for now
+ * to work around a hildon bug.
+ */
+ add_button ("Settings", settings_dialogue);
/* extra buttons for the app menu */
button = gtk_button_new_with_label ("Credits");