summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2012-01-27 16:21:21 +0100
committerAlexander Larsson <alexl@redhat.com>2012-01-27 16:21:21 +0100
commitb0b19005abc37900f7e8b8d002aa2c0e5ffaab7f (patch)
treefcae1a318b72cf9ecabed59e8557af4001141d4d
parent0db26f1d3147df745cb59ad27f568f25987ddb56 (diff)
downloadgnome-contacts-b0b19005abc37900f7e8b8d002aa2c0e5ffaab7f.tar.gz
Add first run dialog
-rw-r--r--configure.ac2
-rw-r--r--src/Makefile.am15
-rw-r--r--src/contacts-app.vala42
-rw-r--r--src/contacts-esd-setup.c45
-rw-r--r--src/contacts-esd-setup.h5
-rw-r--r--src/contacts-list-pane.vala54
-rw-r--r--src/contacts-setup-window.vala213
-rw-r--r--src/contacts-store.vala13
-rw-r--r--src/org.gnome.Contacts.gschema.xml.in10
-rw-r--r--vapi/custom.vapi6
10 files changed, 347 insertions, 58 deletions
diff --git a/configure.ac b/configure.ac
index 315386b..06faef1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -20,6 +20,8 @@ AC_PROG_CC
AM_PROG_VALAC([0.14.0])
AC_PROG_INSTALL
+GLIB_GSETTINGS
+
# i18n stuff
IT_PROG_INTLTOOL([0.40])
diff --git a/src/Makefile.am b/src/Makefile.am
index 18b1e9f..d6ff529 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -35,10 +35,19 @@ vala_sources = \
contacts-avatar-menu.vala \
contacts-contact-frame.vala \
contacts-revealer.vala \
+ contacts-setup-window.vala \
contacts-window.vala \
main.vala \
$(NULL)
+gsettingsschema_in_files = org.gnome.Contacts.gschema.xml.in
+gsettings_SCHEMAS = $(gsettingsschema_in_files:.xml.in=.xml)
+.PRECIOUS: $(gsettings_SCHEMAS)
+
+@INTLTOOL_XML_NOMERGE_RULE@
+
+@GSETTINGS_RULES@
+
contact-resources.c: contacts.gresource.xml app-menu.ui
$(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) $(srcdir)/contacts.gresource.xml \
--target=$@ --sourcedir=$(srcdir) --c-name contacts --generate-source
@@ -52,9 +61,13 @@ gnome_contacts_SOURCES = \
gnome_contacts_LDADD = $(CONTACTS_LIBS) -lm
-CLEANFILES = $(vala_sources:.vala=.c) *.vapi *.stamp
+CLEANFILES = \
+ $(vala_sources:.vala=.c) \
+ $(gsettings_SCHEMAS) \
+ *.vapi *.stamp
EXTRA_DIST = \
gtk-notification.h \
+ $(gsettingsschema_in_files) \
contacts-esd-setup.h \
$(NULL)
diff --git a/src/contacts-app.vala b/src/contacts-app.vala
index 2a7bbad..e0588e8 100644
--- a/src/contacts-app.vala
+++ b/src/contacts-app.vala
@@ -20,6 +20,7 @@ using Gtk;
using Folks;
public class Contacts.App : Gtk.Application {
+ public GLib.Settings settings;
public Contacts.Window window;
public static App app;
public Store contacts_store;
@@ -304,8 +305,46 @@ public class Contacts.App : Gtk.Application {
base.startup ();
}
+ private void show_setup () {
+ avoid_goa_workaround = true;
+ var setup = new SetupWindow ();
+ setup.set_application (this);
+ setup.destroy.connect ( () => {
+ avoid_goa_workaround = false;
+ setup.destroy ();
+ if (setup.succeeded)
+ this.activate ();
+ });
+ setup.show ();
+ }
+
public override void activate () {
if (window == null) {
+ if (!settings.get_boolean ("did-initial-setup")) {
+ if (contacts_store.is_prepared)
+ show_setup ();
+ else {
+ hold ();
+ ulong id = 0;
+ uint id2 = 0;
+ id = contacts_store.prepared.connect (() => {
+ show_setup ();
+ contacts_store.disconnect (id);
+ Source.remove (id2);
+ release ();
+ });
+ // Wait at most 0.5 seconds to show the window
+ id2 = Timeout.add (500, () => {
+ show_setup ();
+ contacts_store.disconnect (id);
+ release ();
+ return false;
+ });
+ }
+
+ return;
+ }
+
create_window ();
// We delay the initial show a tiny bit so most contacts are loaded when we show
@@ -381,7 +420,7 @@ public class Contacts.App : Gtk.Application {
});
overlay.add_overlay (notification);
}
-
+
public override int command_line (ApplicationCommandLine command_line) {
var args = command_line.get_arguments ();
unowned string[] _args = args;
@@ -413,5 +452,6 @@ public class Contacts.App : Gtk.Application {
public App () {
Object (application_id: "org.gnome.Contacts", flags: ApplicationFlags.HANDLES_COMMAND_LINE);
this.app = this;
+ settings = new GLib.Settings ("org.gnome.Contacts");
}
}
diff --git a/src/contacts-esd-setup.c b/src/contacts-esd-setup.c
index 9efeae6..858a654 100644
--- a/src/contacts-esd-setup.c
+++ b/src/contacts-esd-setup.c
@@ -33,7 +33,8 @@ static gboolean created_local = FALSE;
static GMainLoop *goa_loop;
static GoaClient *goa_client;
static GHashTable *accounts;
-static ESourceList *contacts_source_list;
+ESourceList *contacts_source_list;
+gboolean contacts_avoid_goa_workaround = FALSE;
/* This whole file is a gigantic hack that copies and pastes stuff from
* evolution to create evolution-data-server addressbooks as needed.
@@ -176,7 +177,7 @@ ensure_local_addressbook (void)
client = e_book_client_new_system (NULL);
if (client != NULL) {
- contacts_eds_local_store = g_strdup (e_source_peek_uid (e_client_get_source (client)));
+ contacts_eds_local_store = g_strdup (e_source_peek_uid (e_client_get_source (E_CLIENT (client))));
g_object_unref (client);
return TRUE;
}
@@ -345,7 +346,7 @@ online_accounts_account_added_cb (GoaClient *goa_client,
// a while to let a running evo instance
// create the account, this is a lame
// fix for the race condition
- if (goa_loop == NULL) {
+ if (!contacts_avoid_goa_workaround) {
struct SyncData *data = g_new (struct SyncData, 1);
data->uid = g_strdup (evo_id);
data->goa_object = g_object_ref (goa_object);
@@ -559,6 +560,7 @@ void contacts_ensure_eds_accounts (void)
created_local = ensure_local_addressbook ();
goa_loop = g_main_loop_new (NULL, TRUE);
+ contacts_avoid_goa_workaround = TRUE;
online_accounts_connect ();
@@ -567,11 +569,48 @@ void contacts_ensure_eds_accounts (void)
g_main_loop_unref (goa_loop);
goa_loop = NULL;
+ contacts_avoid_goa_workaround = FALSE;
contacts_source_list = NULL;
e_book_get_addressbooks (&contacts_source_list, NULL);
}
+gboolean contacts_has_goa_account (void)
+{
+ GSList *list_a;
+
+ list_a = e_source_list_peek_groups (contacts_source_list);
+ while (list_a != NULL) {
+ ESourceGroup *source_group;
+ GSList *list_b;
+
+ source_group = E_SOURCE_GROUP (list_a->data);
+ list_a = g_slist_next (list_a);
+
+ list_b = e_source_group_peek_sources (source_group);
+
+ while (list_b != NULL) {
+ ESource *source;
+ const gchar *property;
+ const gchar *uid;
+ GList *match;
+
+ source = E_SOURCE (list_b->data);
+ list_b = g_slist_next (list_b);
+
+ uid = e_source_peek_uid (source);
+ property = e_source_get_property (source, GOA_KEY);
+
+ if (property == NULL)
+ continue;
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
/* This is an enourmous hack to find google eds contacts that are
in the "My Contacts" system group. */
diff --git a/src/contacts-esd-setup.h b/src/contacts-esd-setup.h
index 83ed38c..8b4f8e4 100644
--- a/src/contacts-esd-setup.h
+++ b/src/contacts-esd-setup.h
@@ -1,6 +1,11 @@
+#include <libedataserver/e-source-list.h>
+
void contacts_ensure_eds_accounts (void);
extern char *contacts_eds_local_store;
const char *contacts_lookup_esource_name_by_uid (const char *uid);
const char *contacts_lookup_esource_name_by_uid_for_contact (const char *uid);
gboolean contacts_esource_uid_is_google (const char *uid);
char *eds_personal_google_group_name (void);
+gboolean contacts_has_goa_account (void);
+extern ESourceList *contacts_source_list;
+extern gboolean contacts_avoid_goa_workaround;
diff --git a/src/contacts-list-pane.vala b/src/contacts-list-pane.vala
index 0fa2249..4620602 100644
--- a/src/contacts-list-pane.vala
+++ b/src/contacts-list-pane.vala
@@ -25,8 +25,6 @@ public class Contacts.ListPane : Frame {
private ViewWidget list;
public Entry filter_entry;
private uint filter_entry_changed_id;
- private ulong non_empty_id;
- private EventBox empty_box;
private bool ignore_selection_change;
private Revealer search_revealer;
private bool search_visible;
@@ -156,64 +154,14 @@ public class Contacts.ListPane : Frame {
list.show_all ();
scrolled.set_no_show_all (true);
- empty_box = new EventBox ();
- empty_box.set_hexpand (false);
- empty_box.set_vexpand (true);
- empty_box.set_halign (Align.FILL);
- Gdk.RGBA white = {1, 1, 1, 1};
- empty_box.override_background_color (StateFlags.NORMAL, white);
-
- var empty_grid = new Grid ();
- empty_grid.set_row_spacing (8);
- empty_grid.set_orientation (Orientation.VERTICAL);
- empty_grid.set_valign (Align.CENTER);
-
- var image = new Image.from_icon_name ("avatar-default-symbolic", IconSize.DIALOG);
- image.get_style_context ().add_class ("dim-label");
- empty_grid.add (image);
-
- var label = new Label (_("Connect to an account,\nimport or add contacts"));
- label.xalign = 0.5f;
- label.set_hexpand (true);
- label.set_halign (Align.CENTER);
- empty_grid.add (label);
-
- var button = new Button.with_label (_("Online Accounts"));
- button.set_halign (Align.CENTER);
- empty_grid.add (button);
- button.clicked.connect ( (button) => {
- try {
- Process.spawn_command_line_async ("gnome-control-center online-accounts");
- }
- catch (Error e) {
- // TODO: Show error dialog
- }
- });
-
- empty_box.add (empty_grid);
- empty_box.show_all ();
- empty_box.set_no_show_all (true);
-
grid.add (search_revealer);
grid.add (scrolled);
- grid.add (empty_box);
this.show_all ();
search_revealer.set_no_show_all (true);
search_revealer.hide ();
- if (contacts_store.is_empty ()) {
- empty_box.show ();
- non_empty_id = contacts_store.added.connect ( (c) => {
- empty_box.hide ();
- scrolled.show ();
- contacts_store.disconnect (non_empty_id);
- non_empty_id = 0;
- });
- } else {
- scrolled.show ();
- }
-
+ scrolled.show ();
}
public void select_contact (Contact contact, bool ignore_change = false) {
diff --git a/src/contacts-setup-window.vala b/src/contacts-setup-window.vala
new file mode 100644
index 0000000..9f494cc
--- /dev/null
+++ b/src/contacts-setup-window.vala
@@ -0,0 +1,213 @@
+/* -*- Mode: vala; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2011 Alexander Larsson <alexl@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+using Gtk;
+using Folks;
+
+public class Contacts.SetupWindow : Gtk.Window {
+ public bool succeeded;
+ private ulong source_list_changed_id;
+ public Label title_label;
+ public Grid content_grid;
+ ToolButton select_button;
+ ListStore list_store;
+ TreeView tree_view;
+
+ public void update_content () {
+ foreach (var w in content_grid.get_children ())
+ w.destroy ();
+
+ var l = new Label ("");
+ l.set_markup ("<b>%s</b>".printf (_("Welcome to Contacts!")));
+ content_grid.add (l);
+
+ Button goa_button;
+
+ if (has_goa_account ()) {
+ select_button.show ();
+
+ tree_view = new TreeView ();
+ var store = new ListStore (2, typeof (string), typeof (Folks.PersonaStore));
+ list_store = store;
+ tree_view.set_model (store);
+ tree_view.set_headers_visible (false);
+ tree_view.get_selection ().set_mode (SelectionMode.BROWSE);
+
+ var column = new Gtk.TreeViewColumn ();
+ tree_view.append_column (column);
+
+ var renderer = new Gtk.CellRendererText ();
+ column.pack_start (renderer, false);
+ column.add_attribute (renderer, "text", 0);
+
+ var scrolled = new ScrolledWindow(null, null);
+ scrolled.set_size_request (340, 240);
+ scrolled.set_policy (PolicyType.NEVER, PolicyType.AUTOMATIC);
+ scrolled.set_vexpand (true);
+ scrolled.set_shadow_type (ShadowType.IN);
+ scrolled.add (tree_view);
+
+ content_grid.add (scrolled);
+
+ TreeIter iter;
+ foreach (var persona_store in Contact.get_eds_address_books ()) {
+ var name = Contact.format_persona_store_name (persona_store);
+ store.append (out iter);
+ store.set (iter, 0, name, 1, persona_store);
+ if (persona_store == App.app.contacts_store.aggregator.primary_store) {
+ tree_view.get_selection ().select_iter (iter);
+ }
+ }
+
+ goa_button = new Button.with_label (_("Online Account Settings"));
+ content_grid.add (goa_button);
+
+ } else {
+ select_button.hide ();
+ l = new Label (_("Setup an online account or use a local address book"));
+ content_grid.add (l);
+
+ goa_button = new Button.with_label (_("Online Accounts"));
+ content_grid.add (goa_button);
+
+ var b = new Button.with_label (_("Use Local Address Book"));
+ content_grid.add (b);
+
+ b.clicked.connect ( () => {
+ var source = eds_source_list.peek_source_by_uid (eds_local_store);
+ select_source (source);
+ });
+ }
+
+ goa_button.clicked.connect ( (button) => {
+ try {
+ update_content ();
+ Process.spawn_command_line_async ("gnome-control-center online-accounts");
+ }
+ catch (Error e) {
+ // TODO: Show error dialog
+ }
+ });
+
+ content_grid.show_all ();
+ }
+
+ private void select_source (E.Source source) {
+ try {
+ E.BookClient.set_default_source (source);
+ } catch {
+ warning ("Failed to set address book");
+ }
+ succeeded = true;
+ App.app.settings.set_boolean ("did-initial-setup", true);
+ destroy ();
+ }
+
+
+ public SetupWindow () {
+ var grid = new Grid ();
+ this.add (grid);
+ this.set_title (_("Contacts Setup"));
+ this.set_default_size (640, 480);
+
+ this.hide_titlebar_when_maximized = true;
+
+ var toolbar = new Toolbar ();
+ toolbar.set_icon_size (IconSize.MENU);
+ toolbar.get_style_context ().add_class (STYLE_CLASS_MENUBAR);
+ toolbar.set_vexpand (false);
+ toolbar.set_hexpand (true);
+ grid.attach (toolbar, 0, 0, 1, 1);
+
+ var cancel_button = new ToolButton (null, _("Cancel"));
+ cancel_button.is_important = true;
+ toolbar.add (cancel_button);
+ cancel_button.clicked.connect ( (button) => {
+ this.destroy ();
+ });
+
+ var item = new ToolItem ();
+ title_label = new Label ("");
+ title_label.set_markup ("<b>%s</b>".printf (_("Contacts Setup")));
+ title_label.set_no_show_all (true);
+ item.add (title_label);
+ item.set_expand (true);
+ toolbar.add (item);
+
+ select_button = new ToolButton (null, _("Select"));
+ select_button.is_important = true;
+ select_button.set_no_show_all (true);
+ toolbar.add (select_button);
+ select_button.clicked.connect ( (button) => {
+ PersonaStore selected_store;
+ TreeIter iter;
+
+ if (tree_view.get_selection() .get_selected (null, out iter)) {
+ list_store.get (iter, 1, out selected_store);
+
+ var e_store = selected_store as Edsf.PersonaStore;
+ select_source (e_store.source);
+ }
+ });
+
+ var frame = new Frame (null);
+ frame.get_style_context ().add_class ("contacts-content");
+
+ var box = new EventBox ();
+ box.set_hexpand (true);
+ box.set_vexpand (true);
+ box.get_style_context ().add_class ("contacts-main-view");
+ box.get_style_context ().add_class ("view");
+
+ frame.add (box);
+ grid.attach (frame, 0, 1, 1, 1);
+
+ content_grid = new Grid ();
+ content_grid.set_orientation (Orientation.VERTICAL);
+ content_grid.set_halign (Align.CENTER);
+ content_grid.set_row_spacing (8);
+ box.add (content_grid);
+
+ update_content ();
+
+ source_list_changed_id = eds_source_list.changed.connect ( () => {
+ update_content ();
+ });
+
+ grid.show_all ();
+ }
+
+ public override void destroy () {
+ if (source_list_changed_id != 0) {
+ eds_source_list.disconnect (source_list_changed_id);
+ source_list_changed_id = 0;
+ }
+ base.destroy ();
+ }
+
+ public override bool window_state_event (Gdk.EventWindowState e) {
+ base.window_state_event (e);
+
+ if ((e.new_window_state & Gdk.WindowState.MAXIMIZED) != 0)
+ title_label.show ();
+ else
+ title_label.hide ();
+
+ return false;
+ }
+}
diff --git a/src/contacts-store.vala b/src/contacts-store.vala
index 45b8d83..f66ae3b 100644
--- a/src/contacts-store.vala
+++ b/src/contacts-store.vala
@@ -26,6 +26,7 @@ public class Contacts.Store : GLib.Object {
public signal void added (Contact c);
public signal void removed (Contact c);
public signal void quiescent ();
+ public signal void prepared ();
public IndividualAggregator aggregator { get; private set; }
public BackendStore backend_store { get; private set; }
@@ -45,6 +46,10 @@ public class Contacts.Store : GLib.Object {
get { return this.aggregator.is_quiescent; }
}
+ public bool is_prepared {
+ get { return this.aggregator.is_prepared; }
+ }
+
public void refresh () {
foreach (var c in contacts) {
c.queue_changed (true);
@@ -144,6 +149,14 @@ public class Contacts.Store : GLib.Object {
return false;
});
});
+
+ aggregator.notify["is-prepared"].connect ( (obj, pspec) => {
+ Idle.add( () => {
+ this.prepared ();
+ return false;
+ });
+ });
+
aggregator.individuals_changed_detailed.connect ( (changes) => {
// Note: Apparently the current implementation doesn't necessarily pick
// up unlinked individual as replacements.
diff --git a/src/org.gnome.Contacts.gschema.xml.in b/src/org.gnome.Contacts.gschema.xml.in
new file mode 100644
index 0000000..3987072
--- /dev/null
+++ b/src/org.gnome.Contacts.gschema.xml.in
@@ -0,0 +1,10 @@
+<schemalist>
+ <schema id="org.gnome.Contacts" path="/org/gnome/Contacts/" gettext-domain="gnome-contacts">
+ <key name="did-initial-setup" type="b">
+ <default>false</default>
+ <_summary>First-time setup done.</_summary>
+ <_description>Set to true when the user ran the first-time setup wizard.</_description>
+ </key>
+ </schema>
+
+</schemalist>
diff --git a/vapi/custom.vapi b/vapi/custom.vapi
index eace183..d947f9b 100644
--- a/vapi/custom.vapi
+++ b/vapi/custom.vapi
@@ -37,6 +37,12 @@ namespace Contacts {
public static bool esource_uid_is_google (string uid);
[CCode (cname = "eds_personal_google_group_name")]
public static unowned string? eds_personal_google_group_name ();
+ [CCode (cname = "contacts_has_goa_account")]
+ public static bool has_goa_account ();
+ [CCode (cname = "contacts_source_list")]
+ public static E.SourceList eds_source_list;
+ [CCode (cname = "contacts_avoid_goa_workaround")]
+ public static bool avoid_goa_workaround;
}
[CCode (cprefix = "Gtk", lower_case_cprefix = "gtk_", cheader_filename = "gtk-notification.h")]