aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am50
-rw-r--r--src/app-menu.ui19
-rw-r--r--src/gears-menu.ui16
-rw-r--r--src/main.c8
-rw-r--r--src/org.sigxcpu.uplanfahr.gschema.xml20
-rw-r--r--src/prefs.ui78
-rw-r--r--src/tripview.ui103
-rw-r--r--src/uplanfahr.c117
-rw-r--r--src/uplanfahr.gresource.xml10
-rw-r--r--src/uplanfahr.h19
-rw-r--r--src/uplanfahrprefs.c79
-rw-r--r--src/uplanfahrprefs.h20
-rw-r--r--src/uplanfahrtripview.c149
-rw-r--r--src/uplanfahrtripview.h17
-rw-r--r--src/uplanfahrwin.c688
-rw-r--r--src/uplanfahrwin.h23
-rw-r--r--src/window.ui150
17 files changed, 1566 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..2dbeadc
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,50 @@
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ $(WARN_CFLAGS) \
+ $(GTK_CFLAGS) \
+ $(LIBPLANFAHR_CFLAGS)
+ $(NULL)
+
+LDFLAGS = \
+ $(GTK_LIBS) \
+ $(LIBPLANFAHR_LIBS) \
+ $(NULL)
+
+noinst_PROGRAMS = uplanfahr
+
+uplanfahr_SOURCES = \
+ main.c \
+ uplanfahr.c uplanfahr.h \
+ uplanfahrwin.c uplanfahrwin.h \
+ uplanfahrprefs.c uplanfahrprefs.h \
+ uplanfahrtripview.c uplanfahrtripview.h \
+ resources.c
+
+BUILT_SOURCES = \
+ resources.c \
+ gschemas.compiled
+
+resources.c: uplanfahr.gresource.xml $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir) --generate-dependencies $(srcdir)/uplanfahr.gresource.xml)
+ $(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) $(srcdir)/uplanfahr.gresource.xml \
+ --target=$@ --sourcedir=$(srcdir) --generate-source
+
+gsettings_SCHEMAS = \
+ org.sigxcpu.uplanfahr.gschema.xml
+
+@GSETTINGS_RULES@
+
+gschemas.compiled: org.sigxcpu.uplanfahr.gschema.xml
+ $(GLIB_COMPILE_SCHEMAS) .
+
+EXTRA_DIST = \
+ window.ui \
+ app-menu.ui \
+ prefs.ui \
+ gears-menu.ui \
+ tripview.ui \
+ uplanfahr.gresource.xml \
+ org.sigxcpu.uplanfahr.gschema.xml
+
+CLEANFILES = \
+ gschemas.compiled
+
diff --git a/src/app-menu.ui b/src/app-menu.ui
new file mode 100644
index 0000000..b0eddb6
--- /dev/null
+++ b/src/app-menu.ui
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<interface>
+ <!-- interface-requires gtk+ 3.0 -->
+ <menu id="appmenu">
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">_Preferences</attribute>
+ <attribute name="action">app.preferences</attribute>
+ </item>
+ </section>
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">_Quit</attribute>
+ <attribute name="action">app.quit</attribute>
+ <attribute name="accel"><![CDATA[<Ctrl>Q]]></attribute>
+ </item>
+ </section>
+ </menu>
+</interface>
diff --git a/src/gears-menu.ui b/src/gears-menu.ui
new file mode 100644
index 0000000..fb0e929
--- /dev/null
+++ b/src/gears-menu.ui
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<interface>
+ <!-- interface-requires gtk+ 3.0 -->
+ <menu id="menu">
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">_Words</attribute>
+ <attribute name="action">win.show-words</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">_Lines</attribute>
+ <attribute name="action">win.show-lines</attribute>
+ </item>
+ </section>
+ </menu>
+</interface>
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..be59b2d
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,8 @@
+#include <gtk/gtk.h>
+#include <uplanfahr.h>
+
+int
+main (int argc, char *argv[])
+{
+ return g_application_run (G_APPLICATION (u_plan_fahr_new ()), argc, argv);
+}
diff --git a/src/org.sigxcpu.uplanfahr.gschema.xml b/src/org.sigxcpu.uplanfahr.gschema.xml
new file mode 100644
index 0000000..ca6af26
--- /dev/null
+++ b/src/org.sigxcpu.uplanfahr.gschema.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<schemalist>
+ <schema path="/org/sigxcpu/uplanfahr/" id="org.sigxcpu.uplanfahr">
+ <key name="font" type="s">
+ <default>'Monospace 12'</default>
+ <summary>Font</summary>
+ <description>The font to be used for content.</description>
+ </key>
+ <key name="fullscreen" type="b">
+ <default>false</default>
+ <summary>Fullscreen</summary>
+ <description>Whether to display the app fullscreen.</description>
+ </key>
+ <key name="show-words" type="b">
+ <default>false</default>
+ <summary>Show words</summary>
+ <description>Whether to show a word list in the sidebar</description>
+ </key>
+ </schema>
+</schemalist>
diff --git a/src/prefs.ui b/src/prefs.ui
new file mode 100644
index 0000000..833eb36
--- /dev/null
+++ b/src/prefs.ui
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.8 -->
+ <template class="UPlanFahrPrefs" parent="GtkDialog">
+ <property name="title" translatable="yes">Preferences</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="vbox">
+ <child>
+ <object class="GtkGrid" id="grid">
+ <property name="visible">True</property>
+ <property name="margin">6</property>
+ <property name="row-spacing">12</property>
+ <property name="column-spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="fontlabel">
+ <property name="visible">True</property>
+ <property name="label">_Font:</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">font</property>
+ <property name="xalign">1</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFontButton" id="font">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="fullscreenlabel">
+ <property name="visible">True</property>
+ <property name="label">_Fullscreen:</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">fullscreen</property>
+ <property name="xalign">1</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSwitch" id="fullscreen">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="action_area">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkButton" id="close">
+ <signal name="clicked" handler="preferences_closed"/>
+ <property name="visible">True</property>
+ <property name="label">_Close</property>
+ <property name="use-underline">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/src/tripview.ui b/src/tripview.ui
new file mode 100644
index 0000000..f4542ec
--- /dev/null
+++ b/src/tripview.ui
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.16.1 -->
+<interface>
+ <requires lib="gtk+" version="3.10"/>
+ <object class="GtkListStore" id="liststore">
+ <columns>
+ <!-- column-name start -->
+ <column type="LpfStop"/>
+ <!-- column-name end -->
+ <column type="LpfStop"/>
+ <!-- column-name departure_time -->
+ <column type="gchararray"/>
+ <!-- column-name arrival_time -->
+ <column type="gchararray"/>
+ <!-- column-name switches -->
+ <column type="gint"/>
+ <!-- column-name departure_delay -->
+ <column type="gchararray"/>
+ <!-- column-name arrival_delay -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <template class="UPlanFahrTripView" parent="GtkTreeView">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="model">liststore</property>
+ <property name="headers_clickable">False</property>
+ <property name="enable_search">False</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection" id="treeview-selection1"/>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="col_departure_time">
+ <property name="title" translatable="yes">Departure_time</property>
+ <property name="alignment">0.5</property>
+ <child>
+ <object class="GtkCellRendererText" id="cr_departure_time"/>
+ <attributes>
+ <attribute name="markup">2</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="col_departure_delay">
+ <property name="title" translatable="yes">Delay</property>
+ <property name="alignment">0.5</property>
+ <child>
+ <object class="GtkCellRendererText" id="cr_departure_delay"/>
+ <attributes>
+ <attribute name="markup">5</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="col_arrival_time">
+ <property name="title" translatable="yes">Arrival_time</property>
+ <property name="alignment">0.5</property>
+ <child>
+ <object class="GtkCellRendererText" id="cr_arrival_time"/>
+ <attributes>
+ <attribute name="markup">3</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="col_arrival_delay">
+ <property name="title" translatable="yes">Delay</property>
+ <property name="alignment">0.5</property>
+ <child>
+ <object class="GtkCellRendererText" id="cr_arrivaL_delay"/>
+ <attributes>
+ <attribute name="markup">6</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="col_switches">
+ <property name="title" translatable="yes">Switches</property>
+ <property name="alignment">0.5</property>
+ <child>
+ <object class="GtkCellRendererText" id="cr_switches"/>
+ <attributes>
+ <attribute name="markup">4</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="col_status">
+ <property name="title" translatable="yes">Status</property>
+ <property name="alignment">0.5</property>
+ <property name="reorderable">True</property>
+ <child>
+ <object class="GtkCellRendererPixbuf" id="cr_status"/>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/src/uplanfahr.c b/src/uplanfahr.c
new file mode 100644
index 0000000..e87d25e
--- /dev/null
+++ b/src/uplanfahr.c
@@ -0,0 +1,117 @@
+#include <gtk/gtk.h>
+
+#include "uplanfahr.h"
+#include "uplanfahrwin.h"
+#include "uplanfahrprefs.h"
+
+struct _UPlanFahr
+{
+ GtkApplication parent;
+};
+
+struct _UPlanFahrClass
+{
+ GtkApplicationClass parent_class;
+};
+
+G_DEFINE_TYPE(UPlanFahr, u_plan_fahr, GTK_TYPE_APPLICATION);
+
+static void
+u_plan_fahr_init (UPlanFahr *app)
+{
+}
+
+static void
+preferences_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer app)
+{
+ UPlanFahrPrefs *prefs;
+ GtkWindow *win;
+
+ win = gtk_application_get_active_window (GTK_APPLICATION (app));
+ prefs = u_plan_fahr_prefs_new (U_PLAN_FAHR_WINDOW (win));
+ gtk_window_present (GTK_WINDOW (prefs));
+}
+
+static void
+quit_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer app)
+{
+ g_application_quit (G_APPLICATION (app));
+}
+
+static GActionEntry app_entries[] =
+{
+ { "preferences", preferences_activated, NULL, NULL, NULL, {0, 0, 0} },
+ { "quit", quit_activated, NULL, NULL, NULL, {0, 0, 0} }
+};
+
+static void
+u_plan_fahr_startup (GApplication *app)
+{
+ GtkBuilder *builder;
+ GMenuModel *app_menu;
+
+ G_APPLICATION_CLASS (u_plan_fahr_parent_class)->startup (app);
+
+ g_action_map_add_action_entries (G_ACTION_MAP (app),
+ app_entries, G_N_ELEMENTS (app_entries),
+ app);
+
+ builder = gtk_builder_new_from_resource ("/org/sigxcpu/uplanfahr/app-menu.ui");
+ app_menu = G_MENU_MODEL (gtk_builder_get_object (builder, "appmenu"));
+ gtk_application_set_app_menu (GTK_APPLICATION (app), app_menu);
+ g_object_unref (builder);
+}
+
+static void
+u_plan_fahr_activate (GApplication *app)
+{
+ UPlanFahrWindow *win;
+
+ win = u_plan_fahr_window_new (U_PLAN_FAHR (app));
+ gtk_window_present (GTK_WINDOW (win));
+}
+
+static void
+u_plan_fahr_open (GApplication *app,
+ GFile **args,
+ gint n_files,
+ const gchar *hint)
+{
+ GList *windows;
+ UPlanFahrWindow *win;
+ int i;
+
+ windows = gtk_application_get_windows (GTK_APPLICATION (app));
+ if (windows)
+ win = U_PLAN_FAHR_WINDOW (windows->data);
+ else
+ win = u_plan_fahr_window_new (U_PLAN_FAHR (app));
+
+ if (n_files % 2 == 0) {
+ for (i = 0; i < n_files; i+=2)
+ u_plan_fahr_window_open (win, args[i], args[i+1]);
+ }
+
+ gtk_window_present (GTK_WINDOW (win));
+}
+
+static void
+u_plan_fahr_class_init (UPlanFahrClass *class)
+{
+ G_APPLICATION_CLASS (class)->startup = u_plan_fahr_startup;
+ G_APPLICATION_CLASS (class)->activate = u_plan_fahr_activate;
+ G_APPLICATION_CLASS (class)->open = u_plan_fahr_open;
+}
+
+UPlanFahr *
+u_plan_fahr_new (void)
+{
+ return g_object_new (U_PLAN_FAHR_TYPE,
+ "application-id", "org.sigxcpu.org.uplanfahr",
+ "flags", G_APPLICATION_HANDLES_OPEN,
+ NULL);
+}
diff --git a/src/uplanfahr.gresource.xml b/src/uplanfahr.gresource.xml
new file mode 100644
index 0000000..0248133
--- /dev/null
+++ b/src/uplanfahr.gresource.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/org/sigxcpu/uplanfahr">
+ <file preprocess="xml-stripblanks">window.ui</file>
+ <file preprocess="xml-stripblanks">app-menu.ui</file>
+ <file preprocess="xml-stripblanks">gears-menu.ui</file>
+ <file preprocess="xml-stripblanks">tripview.ui</file>
+ <file preprocess="xml-stripblanks">prefs.ui</file>
+ </gresource>
+</gresources>
diff --git a/src/uplanfahr.h b/src/uplanfahr.h
new file mode 100644
index 0000000..5ce2c5a
--- /dev/null
+++ b/src/uplanfahr.h
@@ -0,0 +1,19 @@
+#ifndef __UPLANFAHR_H
+#define __UPLANFAHR_H
+
+#include <gtk/gtk.h>
+
+
+#define U_PLAN_FAHR_TYPE (u_plan_fahr_get_type ())
+#define U_PLAN_FAHR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), U_PLAN_FAHR_TYPE, UPlanFahr))
+
+
+typedef struct _UPlanFahr UPlanFahr;
+typedef struct _UPlanFahrClass UPlanFahrClass;
+
+
+GType u_plan_fahr_get_type (void);
+UPlanFahr *u_plan_fahr_new (void);
+
+
+#endif /* __UPLANFAHR_H */
diff --git a/src/uplanfahrprefs.c b/src/uplanfahrprefs.c
new file mode 100644
index 0000000..49b5f05
--- /dev/null
+++ b/src/uplanfahrprefs.c
@@ -0,0 +1,79 @@
+#include <gtk/gtk.h>
+
+#include "uplanfahr.h"
+#include "uplanfahrwin.h"
+#include "uplanfahrprefs.h"
+
+struct _UPlanFahrPrefs
+{
+ GtkDialog parent;
+};
+
+struct _UPlanFahrPrefsClass
+{
+ GtkDialogClass parent_class;
+};
+
+typedef struct _UPlanFahrPrefsPrivate UPlanFahrPrefsPrivate;
+
+struct _UPlanFahrPrefsPrivate
+{
+ GSettings *settings;
+ GtkWidget *font;
+ GtkWidget *fullscreen;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE(UPlanFahrPrefs, u_plan_fahr_prefs, GTK_TYPE_DIALOG)
+
+static void
+preferences_closed (GtkWidget *button)
+{
+ gtk_widget_destroy (gtk_widget_get_toplevel (button));
+}
+
+static void
+u_plan_fahr_prefs_init (UPlanFahrPrefs *prefs)
+{
+ UPlanFahrPrefsPrivate *priv;
+
+ priv = u_plan_fahr_prefs_get_instance_private (prefs);
+ gtk_widget_init_template (GTK_WIDGET (prefs));
+ priv->settings = g_settings_new ("org.sigxcpu.uplanfahr");
+
+ g_settings_bind (priv->settings, "font",
+ priv->font, "font",
+ G_SETTINGS_BIND_DEFAULT);
+ g_settings_bind (priv->settings, "fullscreen",
+ priv->fullscreen, "active",
+ G_SETTINGS_BIND_DEFAULT);
+}
+
+static void
+u_plan_fahr_prefs_dispose (GObject *object)
+{
+ UPlanFahrPrefsPrivate *priv;
+
+ priv = u_plan_fahr_prefs_get_instance_private (U_PLAN_FAHR_PREFS (object));
+ g_clear_object (&priv->settings);
+
+ G_OBJECT_CLASS (u_plan_fahr_prefs_parent_class)->dispose (object);
+}
+
+static void
+u_plan_fahr_prefs_class_init (UPlanFahrPrefsClass *class)
+{
+ G_OBJECT_CLASS (class)->dispose = u_plan_fahr_prefs_dispose;
+
+ gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
+ "/org/sigxcpu/uplanfahr/prefs.ui");
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class), UPlanFahrPrefs, font);
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class), UPlanFahrPrefs, fullscreen);
+
+ gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), preferences_closed);
+}
+
+UPlanFahrPrefs *
+u_plan_fahr_prefs_new (UPlanFahrWindow *win)
+{
+ return g_object_new (U_PLAN_FAHR_PREFS_TYPE, "transient-for", win, NULL);
+}
diff --git a/src/uplanfahrprefs.h b/src/uplanfahrprefs.h
new file mode 100644
index 0000000..3e8a302
--- /dev/null
+++ b/src/uplanfahrprefs.h
@@ -0,0 +1,20 @@
+#ifndef __UPLANFAHRPREFS_H
+#define __UPLANFAHRPREFS_H
+
+#include <gtk/gtk.h>
+#include "uplanfahrwin.h"
+
+
+#define U_PLAN_FAHR_PREFS_TYPE (u_plan_fahr_prefs_get_type ())
+#define U_PLAN_FAHR_PREFS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), U_PLAN_FAHR_PREFS_TYPE, UPlanFahrPrefs))
+
+
+typedef struct _UPlanFahrPrefs UPlanFahrPrefs;
+typedef struct _UPlanFahrPrefsClass UPlanFahrPrefsClass;
+
+
+GType u_plan_fahr_prefs_get_type (void);
+UPlanFahrPrefs *u_plan_fahr_prefs_new (UPlanFahrWindow *win);
+
+
+#endif /* __UPLANFAHRPREFS_H */
diff --git a/src/uplanfahrtripview.c b/src/uplanfahrtripview.c
new file mode 100644
index 0000000..d36673a
--- /dev/null
+++ b/src/uplanfahrtripview.c
@@ -0,0 +1,149 @@
+#include <gtk/gtk.h>
+
+#include <libplanfahr/libplanfahr.h>
+
+#include "uplanfahr.h"
+#include "uplanfahrtripview.h"
+
+#define COL_START 0
+#define COL_END 1
+#define COL_DEPARTURE_TIME 2
+#define COL_ARRIVAL_TIME 3
+#define COL_PARTS 4
+#define COL_DEPARTURE_DELAY 5
+#define COL_ARRIVAL_DELAY 6
+
+struct _UPlanFahrTripView
+{
+ GtkTreeView parent;
+};
+
+struct _UPlanFahrTripViewClass
+{
+ GtkTreeViewClass parent_class;
+};
+
+typedef struct _UPlanFahrTripViewPrivate UPlanFahrTripViewPrivate;
+
+struct _UPlanFahrTripViewPrivate
+{
+ GtkListStore *liststore;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE(UPlanFahrTripView, u_plan_fahr_trip_view, GTK_TYPE_TREE_VIEW)
+
+static void
+u_plan_fahr_trip_view_init (UPlanFahrTripView *trip_view)
+{
+ gtk_widget_init_template (GTK_WIDGET (trip_view));
+}
+
+static void
+u_plan_fahr_trip_view_dispose (GObject *object)
+{
+ G_OBJECT_CLASS (u_plan_fahr_trip_view_parent_class)->dispose (object);
+}
+
+static void
+u_plan_fahr_trip_view_class_init (UPlanFahrTripViewClass *class)
+{
+ G_OBJECT_CLASS (class)->dispose = u_plan_fahr_trip_view_dispose;
+
+ gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
+ "/org/sigxcpu/uplanfahr/tripview.ui");
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class), UPlanFahrTripView, liststore);
+}
+
+GtkWidget *
+u_plan_fahr_trip_view_new (void)
+{
+ return g_object_new (U_PLAN_FAHR_TRIP_VIEW_TYPE, NULL);
+}
+
+static gchar *
+delay_str (GDateTime *dt, gint delay)
+{
+ gchar sign, *str = NULL;
+
+ if (dt) {
+ if (delay > 0) {
+ sign = '+';
+ } else if (delay < 0) {
+ sign = '-';
+ } else {
+ sign = ' ';
+ }
+ str = g_strdup_printf("%c%d", sign, delay);
+ }
+
+ return str;
+}
+
+void
+u_plan_fahr_trip_view_store_trips (UPlanFahrTripView *self, GSList *trips)
+{
+ UPlanFahrTripViewPrivate *priv;
+ GtkTreeIter iter;
+
+ GSList *parts;
+ LpfTrip *tripobj;
+ LpfTripPart *firstpart, *lastpart;
+ LpfStop *start, *end;
+ GDateTime *arrival, *departure, *rt_departure, *rt_arrival;
+ gchar *deptime, *arrtime, *dep_delay, *arr_delay;
+ gint ddelay, adelay;
+
+ priv = u_plan_fahr_trip_view_get_instance_private (U_PLAN_FAHR_TRIP_VIEW (self));
+
+ gtk_list_store_clear (priv->liststore);
+ for (; trips; trips = g_slist_next (trips)) {
+ tripobj = trips->data;
+ g_object_get(tripobj, "parts", &parts, NULL);
+
+ firstpart = LPF_TRIP_PART(parts->data);
+ lastpart = LPF_TRIP_PART(g_slist_last (parts)->data);
+
+ g_object_get (firstpart, "start", &start, NULL);
+ g_object_get (start,
+ "departure", &departure,
+ "departure_delay", &ddelay,
+ "rt_departure", &rt_departure,
+ NULL);
+ deptime = g_date_time_format (departure, "%H:%M");
+
+ g_object_get (lastpart, "end", &end, NULL);
+ g_object_get (end,
+ "arrival", &arrival,
+ "arrival_delay", &adelay,
+ "rt_arrival", &rt_arrival,
+ NULL);
+ arrtime = g_date_time_format (arrival, "%H:%M");
+
+ dep_delay = delay_str (rt_departure, ddelay);
+ arr_delay = delay_str (rt_arrival, adelay);
+
+ gtk_list_store_append (priv->liststore, &iter);
+ gtk_list_store_set (priv->liststore, &iter,
+ COL_START, start,
+ COL_END, end,
+ COL_DEPARTURE_TIME, deptime,
+ COL_ARRIVAL_TIME, arrtime,
+ COL_PARTS, g_slist_length(parts) - 1,
+ COL_DEPARTURE_DELAY, dep_delay,
+ COL_ARRIVAL_DELAY, arr_delay,
+ -1);
+
+ g_date_time_unref (departure);
+ g_date_time_unref (arrival);
+ g_object_unref (start);
+ g_object_unref (end);
+ if (rt_departure)
+ g_date_time_unref (rt_departure);
+ if (rt_arrival)
+ g_date_time_unref (rt_arrival);
+ g_free (deptime);
+ g_free (arrtime);
+ g_free (dep_delay);
+ g_free (arr_delay);
+ }
+}
diff --git a/src/uplanfahrtripview.h b/src/uplanfahrtripview.h
new file mode 100644
index 0000000..828d99c
--- /dev/null
+++ b/src/uplanfahrtripview.h
@@ -0,0 +1,17 @@
+#ifndef __UPLANFAHRTRIPVIEW_H
+#define __UPLANFAHRTRIPVIEW_H
+
+#include <gtk/gtk.h>
+#include "uplanfahrwin.h"
+
+#define U_PLAN_FAHR_TRIP_VIEW_TYPE (u_plan_fahr_trip_view_get_type ())
+#define U_PLAN_FAHR_TRIP_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), U_PLAN_FAHR_TRIP_VIEW_TYPE, UPlanFahrTripView))
+
+typedef struct _UPlanFahrTripView UPlanFahrTripView;
+typedef struct _UPlanFahrTripViewClass UPlanFahrTripViewClass;
+
+GType u_plan_fahr_trip_view_get_type (void);
+GtkWidget *u_plan_fahr_trip_view_new (void);
+void u_plan_fahr_trip_view_store_trips (UPlanFahrTripView *self, GSList *trips);
+
+#endif /* __UPLANFAHRTRIPVIEW_H */
diff --git a/src/uplanfahrwin.c b/src/uplanfahrwin.c
new file mode 100644
index 0000000..1e4301d
--- /dev/null
+++ b/src/uplanfahrwin.c
@@ -0,0 +1,688 @@
+#include "config.h"
+
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include <libplanfahr/libplanfahr.h>
+
+#include "uplanfahr.h"
+#include "uplanfahrwin.h"
+#include "uplanfahrtripview.h"
+
+LpfProvider *provider;
+LpfManager *manager;
+
+struct _UPlanFahrWindow
+{
+ GtkApplicationWindow parent;
+};
+
+struct _UPlanFahrWindowClass
+{
+ GtkApplicationWindowClass parent_class;
+};
+
+typedef struct _UPlanFahrWindowPrivate UPlanFahrWindowPrivate;
+
+struct _UPlanFahrWindowPrivate
+{
+ GSettings *settings;
+ GtkWidget *stack;
+ GtkWidget *search;
+ GtkWidget *searchbar;
+ GtkWidget *searchentry;
+ GtkWidget *gears;
+ GtkWidget *sidebar;
+ GtkWidget *words;
+ GtkWidget *lines;
+ GtkWidget *lines_label;
+ GtkWidget *popover;
+ GtkWidget *listbox;
+ GtkWidget *start_radiobutton;
+ GtkWidget *tripview;
+
+ gboolean fullscreen;
+ guint searchentry_pulse_id;
+};
+
+enum {
+ LPF_STOP_PROP_0 = 0,
+ U_PLAN_FAHR_WINDOW_PROP_FULLSCREEN,
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE(UPlanFahrWindow, u_plan_fahr_window, GTK_TYPE_APPLICATION_WINDOW);
+
+
+static void
+set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ UPlanFahrWindow *self = U_PLAN_FAHR_WINDOW (object);
+ UPlanFahrWindowPrivate *priv;
+
+ priv = u_plan_fahr_window_get_instance_private (self);
+
+ switch (property_id) {
+ case U_PLAN_FAHR_WINDOW_PROP_FULLSCREEN:
+ priv->fullscreen = g_value_get_boolean (value);
+ if (priv->fullscreen)
+ gtk_window_fullscreen (GTK_WINDOW(self));
+ else
+ gtk_window_unfullscreen (GTK_WINDOW(self));
+ break;
+
+ default:
+ /* We don't have any other property... */
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+
+static void
+get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ UPlanFahrWindow *self = U_PLAN_FAHR_WINDOW (object);
+ UPlanFahrWindowPrivate *priv;
+
+ priv = u_plan_fahr_window_get_instance_private (self);
+
+ switch (property_id) {
+ case U_PLAN_FAHR_WINDOW_PROP_FULLSCREEN:
+ g_value_set_boolean (value, priv->fullscreen);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+
+static gboolean
+window_key_press_event_cb (GtkWidget *win,
+ GdkEvent *event,
+ GtkSearchBar *searchbar)
+{
+ return gtk_search_bar_handle_event (searchbar, event);
+}
+
+
+static void
+got_trips (GSList *trips, gpointer user_data, GError *err)
+{
+ GtkWidget *view = user_data;
+
+ if (err) {
+ g_warning ("%s", err->message);
+ return;
+ }
+
+ g_message ("Found %d trips", g_slist_length (trips));
+
+ u_plan_fahr_trip_view_store_trips (U_PLAN_FAHR_TRIP_VIEW(view), trips);
+}
+
+
+static gboolean
+u_planfahr_get_trips_cb (gpointer user_data)
+{
+ LpfLoc *start, *end;
+ GDateTime *when;
+ GtkWidget *view = GTK_WIDGET(user_data);
+
+ start = g_object_get_data (G_OBJECT(view), "start");
+ end = g_object_get_data (G_OBJECT(view), "end");
+ when = g_date_time_new_now_local ();
+
+ if (start && end && when) {
+ g_message ("Looking for trip from %s to %s", lpf_loc_get_name (start), lpf_loc_get_name (end));
+ lpf_provider_get_trips (provider, start, end, when, 0, got_trips, view);
+ } else {
+ g_message("Missing info");
+ }
+ return G_SOURCE_CONTINUE;
+}
+
+
+static void
+u_planfahr_get_trips (GtkWidget *view)
+{
+ u_planfahr_get_trips_cb (view);
+ g_timeout_add_seconds (30, u_planfahr_get_trips_cb, view);
+}
+
+
+static void
+set_loc (LpfLoc *loc, GtkWidget *view, gboolean is_start)
+{
+ const char *type = is_start ? "start" : "end";
+
+ g_object_set_data (G_OBJECT(view), type, loc);
+}
+
+
+static LpfLoc*
+get_loc (GtkWidget *view, gboolean is_start)
+{
+ const char *type = is_start ? "start" : "end";
+
+ return LPF_LOC(g_object_get_data (G_OBJECT(view), type));
+}
+
+
+static void
+update_title (UPlanFahrWindowPrivate *priv)
+{
+ GtkWidget *tab, *view;
+ LpfLoc *start, *end;
+ gchar *title;
+
+ tab = gtk_stack_get_visible_child (GTK_STACK (priv->stack));
+ view = gtk_bin_get_child (GTK_BIN (tab));
+
+ start = get_loc (view, TRUE);
+ end = get_loc (view, FALSE);
+
+ title = g_strdup_printf ("%s ⇨ %s", lpf_loc_get_name(start), lpf_loc_get_name(end));
+
+ gtk_container_child_set(GTK_CONTAINER(priv->stack), tab, "title", title, NULL);
+
+ g_free (title);
+}
+
+
+static void
+row_activated (GtkListBox *listbox G_GNUC_UNUSED, GtkListBoxRow *row, gpointer user_data)
+{
+ UPlanFahrWindowPrivate *priv = user_data;
+ LpfLoc *loc;
+ gchar *name;
+ GtkWidget *tab, *view;
+ gboolean is_start;
+
+ if (row == NULL)
+ return;
+
+ is_start = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(priv->start_radiobutton));
+
+ loc = LPF_LOC(g_object_get_data (G_OBJECT(row), "loc"));
+ g_return_if_fail (loc != NULL);
+
+ g_object_get (loc, "name", &name, NULL);
+ g_message ("Row activated %s", name);
+ gtk_search_bar_set_search_mode (GTK_SEARCH_BAR(priv->searchbar), FALSE);
+
+ tab = gtk_stack_get_visible_child (GTK_STACK (priv->stack));
+ view = gtk_bin_get_child (GTK_BIN (tab));
+
+ set_loc (loc, view, is_start);
+ update_title (priv);
+
+ u_planfahr_get_trips (view);
+
+ gtk_widget_hide (GTK_WIDGET(priv->popover));
+ g_free (name);
+}
+
+
+static void
+clear_search_popover(UPlanFahrWindowPrivate *priv)
+{
+ GList *iter, *children;
+
+ children = gtk_container_get_children(GTK_CONTAINER(priv->listbox));
+ for(iter = children; iter != NULL; iter = g_list_next(iter))
+ gtk_container_remove(GTK_CONTAINER(priv->listbox), GTK_WIDGET(iter->data));
+ g_list_free(children);
+}
+
+
+static void
+popover_closed (GtkPopover *popover, UPlanFahrWindowPrivate *priv)
+{
+ /* popup closed without selection, back to searchentry */
+ gtk_widget_grab_focus (priv->searchentry);
+ gtk_editable_set_position (GTK_EDITABLE(priv->searchentry), -1);
+}
+
+static gboolean
+searchentry_pulse_step(GtkEntry *entry)
+{
+ gtk_entry_progress_pulse (entry);
+ return TRUE;
+}
+
+
+static void
+searchentry_start_progressbar (UPlanFahrWindowPrivate *priv)
+{
+ gtk_entry_set_progress_pulse_step (GTK_ENTRY(priv->searchentry), 0.25);
+ searchentry_pulse_step (GTK_ENTRY (priv->searchentry));
+ if (!priv->searchentry_pulse_id)
+ priv->searchentry_pulse_id = g_timeout_add_seconds (1, (GSourceFunc)searchentry_pulse_step, GTK_ENTRY(priv->searchentry));
+}
+
+
+static void
+searchentry_stop_progressbar (UPlanFahrWindowPrivate *priv)
+{
+ if (priv->searchentry_pulse_id)
+ g_source_remove (priv->searchentry_pulse_id);
+ gtk_entry_set_progress_pulse_step (GTK_ENTRY(priv->searchentry), 0);
+ priv->searchentry_pulse_id = 0;
+}
+
+
+static void
+populate_search_popover(GSList *locs, gpointer user_data, GError *err)
+{
+ UPlanFahrWindow *win;
+ UPlanFahrWindowPrivate *priv;
+ GtkEntry *entry = GTK_ENTRY(user_data);
+ GtkWidget *label, *row;
+ LpfLoc *loc;
+ GSList *iter;
+ gchar *name;
+
+ win = U_PLAN_FAHR_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (entry)));
+ priv = u_plan_fahr_window_get_instance_private (win);
+
+ if (err) {
+ g_warning ("%s", err->message);
+ return;
+ }
+
+ g_message("Found %d locs", g_slist_length(locs));
+ for (iter = locs; iter; iter = g_slist_next (iter)) {
+ loc = iter->data;
+ g_object_get (loc, "name", &name, NULL);
+ label = gtk_label_new(name);
+ row = gtk_list_box_row_new ();
+ g_object_set_data (G_OBJECT(row), "loc", loc);
+ gtk_container_add (GTK_CONTAINER(row), label);
+ gtk_list_box_insert (GTK_LIST_BOX(priv->listbox), row, -1);
+ }
+
+ row = GTK_WIDGET (gtk_list_box_get_row_at_index (GTK_LIST_BOX(priv->listbox), 0));
+ gtk_list_box_select_row ( GTK_LIST_BOX(priv->listbox), GTK_LIST_BOX_ROW(row));
+
+ searchentry_stop_progressbar (priv);
+
+ gtk_widget_show_all (priv->popover);
+}
+
+
+static void
+trigger_populate_search_popover(UPlanFahrWindowPrivate *priv, const gchar *text)
+{
+ g_message ("Searching for %s", text);
+ lpf_provider_get_locs (provider, text, 0, populate_search_popover, priv->searchentry);
+ searchentry_start_progressbar (priv);
+}
+
+
+static void
+searchentry_text_changed (GtkEntry *entry)
+{
+ UPlanFahrWindow *win;
+ UPlanFahrWindowPrivate *priv;
+ const gchar *text;
+
+ win = U_PLAN_FAHR_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (entry)));
+ priv = u_plan_fahr_window_get_instance_private (win);
+
+ clear_search_popover(priv);
+ text = gtk_entry_get_text (entry);
+
+ if (text[0] == '\0') {
+ gtk_widget_hide (priv->popover);
+ return;
+ }
+
+ searchentry_start_progressbar (priv);
+
+ trigger_populate_search_popover (priv, text);
+}
+
+
+static void
+update_words (UPlanFahrWindow *win)
+{
+#if 0
+ UPlanFahrWindowPrivate *priv;
+ GHashTable *strings;
+ GHashTableIter iter;
+ GtkWidget *tab, *view, *row;
+ GtkTextBuffer *buffer;
+ GtkTextIter start, end;
+ GList *children, *l;
+ gchar *word, *key;
+
+ priv = u_plan_fahr_window_get_instance_private (win);
+
+ tab = gtk_stack_get_visible_child (GTK_STACK (priv->stack));
+
+ if (tab == NULL)
+ return;
+
+ view = gtk_bin_get_child (GTK_BIN (tab));
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+
+ strings = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+ gtk_text_buffer_get_start_iter (buffer, &start);
+ while (!gtk_text_iter_is_end (&start))
+ {
+ while (!gtk_text_iter_starts_word (&start))
+ {
+ if (!gtk_text_iter_forward_char (&start))
+ goto done;
+ }
+ end = start;
+ if (!gtk_text_iter_forward_word_end (&end))
+ goto done;
+ word = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
+ g_hash_table_add (strings, g_utf8_strdown (word, -1));
+ g_free (word);
+ start = end;
+ }
+
+ done:
+ children = gtk_container_get_children (GTK_CONTAINER (priv->words));
+ for (l = children; l; l = l->next)
+ gtk_container_remove (GTK_CONTAINER (priv->words), GTK_WIDGET (l->data));
+ g_list_free (children);
+
+ g_hash_table_iter_init (&iter, strings);
+ while (g_hash_table_iter_next (&iter, (gpointer *)&key, NULL))
+ {
+ row = gtk_button_new_with_label (key);
+ g_signal_connect (row, "clicked",
+ G_CALLBACK (find_word), win);
+ gtk_widget_show (row);
+ gtk_container_add (GTK_CONTAINER (priv->words), row);
+ }
+
+ g_hash_table_unref (strings);
+#endif
+}
+
+
+static void
+update_lines (UPlanFahrWindow *win)
+{
+#if 0
+ UPlanFahrWindowPrivate *priv;
+ GtkWidget *tab, *view;
+ GtkTextBuffer *buffer;
+ GtkTextIter iter;
+ int count;
+ gchar *lines;
+
+ priv = u_plan_fahr_window_get_instance_private (win);
+
+ tab = gtk_stack_get_visible_child (GTK_STACK (priv->stack));
+
+ if (tab == NULL)
+ return;
+
+ view = gtk_bin_get_child (GTK_BIN (tab));
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+
+ count = 0;
+
+ gtk_text_buffer_get_start_iter (buffer, &iter);
+ while (!gtk_text_iter_is_end (&iter))
+ {
+ count++;
+ if (!gtk_text_iter_forward_line (&iter))
+ break;
+ }
+
+ lines = g_strdup_printf ("%d", count);
+ gtk_label_set_text (GTK_LABEL (priv->lines), lines);
+ g_free (lines);
+#endif
+}
+
+
+static void
+visible_child_changed (GObject *stack,
+ GParamSpec *pspec)
+{
+#if 0
+ UPlanFahrWindow *win;
+ UPlanFahrWindowPrivate *priv;
+
+ if (gtk_widget_in_destruction (GTK_WIDGET (stack)))
+ return;
+
+ win = U_PLAN_FAHR_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (stack)));
+ priv = u_plan_fahr_window_get_instance_private (win);
+ gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (priv->searchbar), FALSE);
+ update_words (win);
+ update_lines (win);
+#endif
+}
+
+
+static void
+words_changed (GObject *sidebar,
+ GParamSpec *pspec,
+ UPlanFahrWindow *win)
+{
+ update_words (win);
+}
+
+
+static void
+u_plan_fahr_window_init (UPlanFahrWindow *win)
+{
+ UPlanFahrWindowPrivate *priv;
+ GtkBuilder *builder;
+ GMenuModel *menu;
+ GAction *action;
+
+ priv = u_plan_fahr_window_get_instance_private (win);
+ gtk_widget_init_template (GTK_WIDGET (win));
+ priv->settings = g_settings_new ("org.sigxcpu.uplanfahr");
+
+ g_settings_bind (priv->settings, "fullscreen",
+ win, "fullscreen",
+ G_SETTINGS_BIND_DEFAULT);
+
+ g_settings_bind (priv->settings, "show-words",
+ priv->sidebar, "reveal-child",
+ G_SETTINGS_BIND_DEFAULT);
+
+ g_object_bind_property (priv->search, "active",
+ priv->searchbar, "search-mode-enabled",
+ G_BINDING_BIDIRECTIONAL);
+
+ g_signal_connect (priv->sidebar, "notify::reveal-child",
+ G_CALLBACK (words_changed), win);
+
+ builder = gtk_builder_new_from_resource ("/org/sigxcpu/uplanfahr/gears-menu.ui");
+ menu = G_MENU_MODEL (gtk_builder_get_object (builder, "menu"));
+ gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (priv->gears), menu);
+ g_object_unref (builder);
+
+ action = g_settings_create_action (priv->settings, "show-words");
+ g_action_map_add_action (G_ACTION_MAP (win), action);
+ g_object_unref (action);
+
+ action = (GAction*) g_property_action_new ("show-lines", priv->lines, "visible");
+ g_action_map_add_action (G_ACTION_MAP (win), action);
+ g_object_unref (action);
+
+ g_object_bind_property (priv->lines, "visible",
+ priv->lines_label, "visible",
+ G_BINDING_DEFAULT);
+
+ gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
+
+ /* search bar and popup */
+ priv->listbox = gtk_list_box_new ();
+
+ priv->popover = gtk_popover_new (GTK_WIDGET (priv->searchentry));
+ gtk_style_context_add_class (gtk_widget_get_style_context (priv->popover),
+ GTK_STYLE_CLASS_OSD);
+ gtk_popover_set_position (GTK_POPOVER(priv->popover), GTK_POS_BOTTOM);
+ gtk_popover_set_modal (GTK_POPOVER (priv->popover), FALSE);
+ gtk_container_add (GTK_CONTAINER (priv->popover),
+ priv->listbox);
+ gtk_container_set_border_width (GTK_CONTAINER (priv->popover), 4);
+
+ g_signal_connect (priv->popover, "closed",
+ G_CALLBACK (popover_closed), priv);
+
+ g_signal_connect (priv->listbox, "row-activated",
+ G_CALLBACK (row_activated), priv);
+
+ g_signal_connect (win, "key-press-event",
+ G_CALLBACK (window_key_press_event_cb), priv->searchbar);
+
+ gtk_widget_show (priv->listbox);
+}
+
+
+static void
+u_plan_fahr_window_dispose (GObject *object)
+{
+ UPlanFahrWindow *win;
+ UPlanFahrWindowPrivate *priv;
+
+ win = U_PLAN_FAHR_WINDOW (object);
+ priv = u_plan_fahr_window_get_instance_private (win);
+
+ g_clear_object (&priv->settings);
+
+ G_OBJECT_CLASS (u_plan_fahr_window_parent_class)->dispose (object);
+}
+
+
+static void
+u_plan_fahr_window_class_init (UPlanFahrWindowClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->dispose = u_plan_fahr_window_dispose;
+
+ gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
+ "/org/sigxcpu/uplanfahr/window.ui");
+
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class), UPlanFahrWindow, stack);
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class), UPlanFahrWindow, search);
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class), UPlanFahrWindow, searchbar);
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class), UPlanFahrWindow, searchentry);
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class), UPlanFahrWindow, gears);
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class), UPlanFahrWindow, words);
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class), UPlanFahrWindow, sidebar);
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class), UPlanFahrWindow, lines);
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class), UPlanFahrWindow, lines_label);
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class), UPlanFahrWindow, start_radiobutton);
+
+ gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), searchentry_text_changed);
+ gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), visible_child_changed);
+
+ object_class->set_property = set_property;
+ object_class->get_property = get_property;
+
+ g_object_class_install_property (object_class,
+ U_PLAN_FAHR_WINDOW_PROP_FULLSCREEN,
+ g_param_spec_boolean ("fullscreen",
+ "Fullscreen",
+ "Fullscreen window",
+ FALSE,
+ G_PARAM_READWRITE));
+}
+
+UPlanFahrWindow *
+u_plan_fahr_window_new (UPlanFahr *app)
+{
+ UPlanFahrWindow *win;
+
+ win = g_object_new (U_PLAN_FAHR_WINDOW_TYPE, "application", app, NULL);
+
+ return win;
+}
+
+
+
+
+static void
+initial_got_start (GSList *locs, gpointer user_data, GError *err)
+{
+ GtkWidget *view = GTK_WIDGET(user_data);
+
+ if (err) {
+ g_warning ("%s", err->message);
+ return;
+ }
+
+ set_loc (locs->data, view, TRUE);
+}
+
+
+static void
+initial_got_end (GSList *locs, gpointer user_data, GError *err)
+{
+ GtkWidget *view = GTK_WIDGET(user_data);
+
+ if (err) {
+ g_warning ("%s", err->message);
+ return;
+ }
+
+ set_loc (locs->data, view, FALSE);
+ u_planfahr_get_trips (view);
+}
+
+
+void
+u_plan_fahr_window_open (UPlanFahrWindow *win,
+ GFile *from,
+ GFile *to)
+{
+ UPlanFahrWindowPrivate *priv;
+ GtkWidget *scrolled, *view;
+ gchar *fromname, *toname, *title;
+
+ priv = u_plan_fahr_window_get_instance_private (win);
+
+ /* use the first two args as from and to */
+ fromname = g_file_get_basename(from);
+ toname = g_file_get_basename(to);
+
+ title = g_strdup_printf ("%s ⇨ %s", fromname, toname);
+
+ scrolled = gtk_scrolled_window_new (NULL, NULL);
+ gtk_widget_show (scrolled);
+ gtk_widget_set_hexpand (scrolled, TRUE);
+ gtk_widget_set_vexpand (scrolled, TRUE);
+ view = u_plan_fahr_trip_view_new ();
+ gtk_widget_show (view);
+
+ gtk_container_add (GTK_CONTAINER (scrolled), view);
+ gtk_stack_add_titled (GTK_STACK (priv->stack), scrolled, title, title);
+ g_free (title);
+
+ /* FIXME: move out and fill initial data */
+ manager = lpf_manager_new();
+ provider = lpf_manager_activate_provider(manager, "de-db", NULL);
+ lpf_provider_get_locs(provider, fromname, 0, initial_got_start, view);
+ lpf_provider_get_locs(provider, toname, 0, initial_got_end, view);
+
+ gtk_widget_set_sensitive (priv->search, TRUE);
+
+ update_words (win);
+ update_lines (win);
+
+ g_free (title);
+}
diff --git a/src/uplanfahrwin.h b/src/uplanfahrwin.h
new file mode 100644
index 0000000..9decaf7
--- /dev/null
+++ b/src/uplanfahrwin.h
@@ -0,0 +1,23 @@
+#ifndef __UPLANFAHRWIN_H
+#define __UPLANFAHRWIN_H
+
+#include <gtk/gtk.h>
+#include "uplanfahr.h"
+
+
+#define U_PLAN_FAHR_WINDOW_TYPE (u_plan_fahr_window_get_type ())
+#define U_PLAN_FAHR_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), U_PLAN_FAHR_WINDOW_TYPE, UPlanFahrWindow))
+
+
+typedef struct _UPlanFahrWindow UPlanFahrWindow;
+typedef struct _UPlanFahrWindowClass UPlanFahrWindowClass;
+
+
+GType u_plan_fahr_window_get_type (void);
+UPlanFahrWindow *u_plan_fahr_window_new (UPlanFahr *app);
+void u_plan_fahr_window_open (UPlanFahrWindow *win,
+ GFile *from,
+ GFile *to);
+
+
+#endif /* __UPLANFAHRWIN_H */
diff --git a/src/window.ui b/src/window.ui
new file mode 100644
index 0000000..c6c7d1f
--- /dev/null
+++ b/src/window.ui
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.8 -->
+ <template class="UPlanFahrWindow" parent="GtkApplicationWindow">
+ <property name="title" translatable="yes">UPlanFahr</property>
+ <property name="default-width">600</property>
+ <property name="default-height">400</property>
+ <child type="titlebar">
+ <object class="GtkHeaderBar" id="header">
+ <property name="visible">True</property>
+ <property name="show-close-button">True</property>
+ <child>
+ <object class="GtkLabel" id="lines_label">
+ <property name="visible">False</property>
+ <property name="label" translatable="yes">Lines:</property>
+ </object>
+ <packing>
+ <property name="pack-type">start</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="lines">
+ <property name="visible">False</property>
+ </object>
+ <packing>
+ <property name="pack-type">start</property>
+ </packing>
+ </child>
+ <child type="title">
+ <object class="GtkStackSwitcher" id="tabs">
+ <property name="visible">True</property>
+ <property name="stack">stack</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="search">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <child>
+ <object class="GtkImage" id="search-icon">
+ <property name="visible">True</property>
+ <property name="icon-name">edit-find-symbolic</property>
+ <property name="icon-size">1</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="pack-type">end</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="gears">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkImage" id="gears-icon">
+ <property name="visible">True</property>
+ <property name="icon-name">emblem-system-symbolic</property>
+ <property name="icon-size">1</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="pack-type">end</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox" id="content_box">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkSearchBar" id="searchbar">
+ <property name="visible">True</property>
+
+ <child>
+ <object class="GtkSearchEntry" id="searchentry">
+ <signal name="search-changed" handler="searchentry_text_changed"/>
+ <property name="visible">True</property>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+
+ <child>
+ <object class="GtkRadioButton" id="start_radiobutton">
+ <property name="label" translatable="yes">Start</property>
+ <property name="visible">True</property>
+ <property name="active">False</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="stop_radiobutton">
+ <property name="label" translatable="yes">End</property>
+ <property name="visible">True</property>
+ <property name="group">start_radiobutton</property>
+ <property name="active">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox" id="hbox">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkRevealer" id="sidebar">
+ <property name="visible">True</property>
+ <property name="transition-type">slide-right</property>
+ <child>
+ <object class="GtkScrolledWindow" id="sidebar-sw">
+ <property name="visible">True</property>
+ <property name="hscrollbar-policy">never</property>
+ <property name="vscrollbar-policy">automatic</property>
+ <child>
+ <object class="GtkListBox" id="words">
+ <property name="visible">True</property>
+ <property name="selection-mode">none</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkStack" id="stack">
+ <signal name="notify::visible-child" handler="visible_child_changed"/>
+ <property name="visible">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>