Rename all filenames starting with "gossip" by "empathy", change namespace
authorXavier Claessens <xclaesse@gmail.com>
Fri, 22 Jun 2007 10:47:42 +0000 (10:47 +0000)
committerXavier Claessens <xclaesse@src.gnome.org>
Fri, 22 Jun 2007 10:47:42 +0000 (10:47 +0000)
2007-06-22 Xavier Claessens  <xclaesse@gmail.com>

* libempathy/*.[ch]:
* libempathy-gtk/*.[ch]:
* src/*.[ch]: Rename all filenames starting with "gossip" by "empathy",
change namespace of all gossip_*() functions to empathy_*().
Fixes bug #444490 (Mario Danic, Xavier Claessens).

svn path=/trunk/; revision=170

205 files changed:
ChangeLog
TODO
libempathy-gtk/Makefile.am
libempathy-gtk/empathy-about-dialog.c [new file with mode: 0644]
libempathy-gtk/empathy-about-dialog.h [new file with mode: 0644]
libempathy-gtk/empathy-account-chooser.c [new file with mode: 0644]
libempathy-gtk/empathy-account-chooser.h [new file with mode: 0644]
libempathy-gtk/empathy-account-widget-generic.c [new file with mode: 0644]
libempathy-gtk/empathy-account-widget-generic.h [new file with mode: 0644]
libempathy-gtk/empathy-account-widget-jabber.c [new file with mode: 0644]
libempathy-gtk/empathy-account-widget-jabber.glade [new file with mode: 0644]
libempathy-gtk/empathy-account-widget-jabber.h [new file with mode: 0644]
libempathy-gtk/empathy-accounts-dialog.c [new file with mode: 0644]
libempathy-gtk/empathy-accounts-dialog.glade [new file with mode: 0644]
libempathy-gtk/empathy-accounts-dialog.h [new file with mode: 0644]
libempathy-gtk/empathy-cell-renderer-expander.c [new file with mode: 0644]
libempathy-gtk/empathy-cell-renderer-expander.h [new file with mode: 0644]
libempathy-gtk/empathy-cell-renderer-text.c [new file with mode: 0644]
libempathy-gtk/empathy-cell-renderer-text.h [new file with mode: 0644]
libempathy-gtk/empathy-chat-view.c [new file with mode: 0644]
libempathy-gtk/empathy-chat-view.h [new file with mode: 0644]
libempathy-gtk/empathy-chat-window.c [new file with mode: 0644]
libempathy-gtk/empathy-chat-window.h [new file with mode: 0644]
libempathy-gtk/empathy-chat.c [new file with mode: 0644]
libempathy-gtk/empathy-chat.glade [new file with mode: 0644]
libempathy-gtk/empathy-chat.h [new file with mode: 0644]
libempathy-gtk/empathy-chatrooms-window.c [new file with mode: 0644]
libempathy-gtk/empathy-chatrooms-window.glade [new file with mode: 0644]
libempathy-gtk/empathy-chatrooms-window.h [new file with mode: 0644]
libempathy-gtk/empathy-contact-dialogs.c
libempathy-gtk/empathy-contact-dialogs.h
libempathy-gtk/empathy-contact-groups.c [new file with mode: 0644]
libempathy-gtk/empathy-contact-groups.dtd [new file with mode: 0644]
libempathy-gtk/empathy-contact-groups.h [new file with mode: 0644]
libempathy-gtk/empathy-contact-list-store.c [new file with mode: 0644]
libempathy-gtk/empathy-contact-list-store.h [new file with mode: 0644]
libempathy-gtk/empathy-contact-list-view.c [new file with mode: 0644]
libempathy-gtk/empathy-contact-list-view.h [new file with mode: 0644]
libempathy-gtk/empathy-contact-widget.c
libempathy-gtk/empathy-contact-widget.h
libempathy-gtk/empathy-geometry.c [new file with mode: 0644]
libempathy-gtk/empathy-geometry.h [new file with mode: 0644]
libempathy-gtk/empathy-group-chat.c [new file with mode: 0644]
libempathy-gtk/empathy-group-chat.glade [new file with mode: 0644]
libempathy-gtk/empathy-group-chat.h [new file with mode: 0644]
libempathy-gtk/empathy-log-window.c [new file with mode: 0644]
libempathy-gtk/empathy-log-window.glade [new file with mode: 0644]
libempathy-gtk/empathy-log-window.h [new file with mode: 0644]
libempathy-gtk/empathy-main-window.c
libempathy-gtk/empathy-new-chatroom-dialog.c [new file with mode: 0644]
libempathy-gtk/empathy-new-chatroom-dialog.glade [new file with mode: 0644]
libempathy-gtk/empathy-new-chatroom-dialog.h [new file with mode: 0644]
libempathy-gtk/empathy-preferences.c [new file with mode: 0644]
libempathy-gtk/empathy-preferences.glade [new file with mode: 0644]
libempathy-gtk/empathy-preferences.h [new file with mode: 0644]
libempathy-gtk/empathy-presence-chooser.c [new file with mode: 0644]
libempathy-gtk/empathy-presence-chooser.glade [new file with mode: 0644]
libempathy-gtk/empathy-presence-chooser.h [new file with mode: 0644]
libempathy-gtk/empathy-private-chat.c [new file with mode: 0644]
libempathy-gtk/empathy-private-chat.h [new file with mode: 0644]
libempathy-gtk/empathy-profile-chooser.c [new file with mode: 0644]
libempathy-gtk/empathy-profile-chooser.h [new file with mode: 0644]
libempathy-gtk/empathy-spell-dialog.c [new file with mode: 0644]
libempathy-gtk/empathy-spell-dialog.glade [new file with mode: 0644]
libempathy-gtk/empathy-spell-dialog.h [new file with mode: 0644]
libempathy-gtk/empathy-spell.c [new file with mode: 0644]
libempathy-gtk/empathy-spell.h [new file with mode: 0644]
libempathy-gtk/empathy-status-icon.c
libempathy-gtk/empathy-status-presets.c [new file with mode: 0644]
libempathy-gtk/empathy-status-presets.dtd [new file with mode: 0644]
libempathy-gtk/empathy-status-presets.h [new file with mode: 0644]
libempathy-gtk/empathy-theme-manager.c [new file with mode: 0644]
libempathy-gtk/empathy-theme-manager.h [new file with mode: 0644]
libempathy-gtk/empathy-ui-utils.c [new file with mode: 0644]
libempathy-gtk/empathy-ui-utils.h [new file with mode: 0644]
libempathy-gtk/gossip-about-dialog.c [deleted file]
libempathy-gtk/gossip-about-dialog.h [deleted file]
libempathy-gtk/gossip-account-chooser.c [deleted file]
libempathy-gtk/gossip-account-chooser.h [deleted file]
libempathy-gtk/gossip-account-widget-generic.c [deleted file]
libempathy-gtk/gossip-account-widget-generic.h [deleted file]
libempathy-gtk/gossip-account-widget-jabber.c [deleted file]
libempathy-gtk/gossip-account-widget-jabber.glade [deleted file]
libempathy-gtk/gossip-account-widget-jabber.h [deleted file]
libempathy-gtk/gossip-accounts-dialog.c [deleted file]
libempathy-gtk/gossip-accounts-dialog.glade [deleted file]
libempathy-gtk/gossip-accounts-dialog.h [deleted file]
libempathy-gtk/gossip-cell-renderer-expander.c [deleted file]
libempathy-gtk/gossip-cell-renderer-expander.h [deleted file]
libempathy-gtk/gossip-cell-renderer-text.c [deleted file]
libempathy-gtk/gossip-cell-renderer-text.h [deleted file]
libempathy-gtk/gossip-chat-manager.loT [deleted file]
libempathy-gtk/gossip-chat-view.c [deleted file]
libempathy-gtk/gossip-chat-view.h [deleted file]
libempathy-gtk/gossip-chat-window.c [deleted file]
libempathy-gtk/gossip-chat-window.h [deleted file]
libempathy-gtk/gossip-chat.c [deleted file]
libempathy-gtk/gossip-chat.glade [deleted file]
libempathy-gtk/gossip-chat.h [deleted file]
libempathy-gtk/gossip-chatrooms-window.c [deleted file]
libempathy-gtk/gossip-chatrooms-window.glade [deleted file]
libempathy-gtk/gossip-chatrooms-window.h [deleted file]
libempathy-gtk/gossip-contact-groups.c [deleted file]
libempathy-gtk/gossip-contact-groups.dtd [deleted file]
libempathy-gtk/gossip-contact-groups.h [deleted file]
libempathy-gtk/gossip-contact-list-store.c [deleted file]
libempathy-gtk/gossip-contact-list-store.h [deleted file]
libempathy-gtk/gossip-contact-list-view.c [deleted file]
libempathy-gtk/gossip-contact-list-view.h [deleted file]
libempathy-gtk/gossip-geometry.c [deleted file]
libempathy-gtk/gossip-geometry.h [deleted file]
libempathy-gtk/gossip-group-chat.c [deleted file]
libempathy-gtk/gossip-group-chat.glade [deleted file]
libempathy-gtk/gossip-group-chat.h [deleted file]
libempathy-gtk/gossip-log-window.c [deleted file]
libempathy-gtk/gossip-log-window.glade [deleted file]
libempathy-gtk/gossip-log-window.h [deleted file]
libempathy-gtk/gossip-new-chatroom-dialog.c [deleted file]
libempathy-gtk/gossip-new-chatroom-dialog.glade [deleted file]
libempathy-gtk/gossip-new-chatroom-dialog.h [deleted file]
libempathy-gtk/gossip-preferences.c [deleted file]
libempathy-gtk/gossip-preferences.glade [deleted file]
libempathy-gtk/gossip-preferences.h [deleted file]
libempathy-gtk/gossip-presence-chooser.c [deleted file]
libempathy-gtk/gossip-presence-chooser.glade [deleted file]
libempathy-gtk/gossip-presence-chooser.h [deleted file]
libempathy-gtk/gossip-private-chat.c [deleted file]
libempathy-gtk/gossip-private-chat.h [deleted file]
libempathy-gtk/gossip-profile-chooser.c [deleted file]
libempathy-gtk/gossip-profile-chooser.h [deleted file]
libempathy-gtk/gossip-spell-dialog.c [deleted file]
libempathy-gtk/gossip-spell-dialog.glade [deleted file]
libempathy-gtk/gossip-spell-dialog.h [deleted file]
libempathy-gtk/gossip-spell.c [deleted file]
libempathy-gtk/gossip-spell.h [deleted file]
libempathy-gtk/gossip-status-presets.c [deleted file]
libempathy-gtk/gossip-status-presets.dtd [deleted file]
libempathy-gtk/gossip-status-presets.h [deleted file]
libempathy-gtk/gossip-theme-manager.c [deleted file]
libempathy-gtk/gossip-theme-manager.h [deleted file]
libempathy-gtk/gossip-ui-utils.c [deleted file]
libempathy-gtk/gossip-ui-utils.h [deleted file]
libempathy/Makefile.am
libempathy/empathy-avatar.c [new file with mode: 0644]
libempathy/empathy-avatar.h [new file with mode: 0644]
libempathy/empathy-chandler.c
libempathy/empathy-chatroom-manager.c [new file with mode: 0644]
libempathy/empathy-chatroom-manager.dtd [new file with mode: 0644]
libempathy/empathy-chatroom-manager.h [new file with mode: 0644]
libempathy/empathy-chatroom.c [new file with mode: 0644]
libempathy/empathy-chatroom.h [new file with mode: 0644]
libempathy/empathy-conf.c [new file with mode: 0644]
libempathy/empathy-conf.h [new file with mode: 0644]
libempathy/empathy-contact-list.c
libempathy/empathy-contact-list.h
libempathy/empathy-contact-manager.c
libempathy/empathy-contact-manager.h
libempathy/empathy-contact.c [new file with mode: 0644]
libempathy/empathy-contact.h [new file with mode: 0644]
libempathy/empathy-debug.c [new file with mode: 0644]
libempathy/empathy-debug.h [new file with mode: 0644]
libempathy/empathy-idle.c
libempathy/empathy-log-manager.c
libempathy/empathy-log-manager.h
libempathy/empathy-message.c [new file with mode: 0644]
libempathy/empathy-message.h [new file with mode: 0644]
libempathy/empathy-presence.c [new file with mode: 0644]
libempathy/empathy-presence.h [new file with mode: 0644]
libempathy/empathy-time.c [new file with mode: 0644]
libempathy/empathy-time.h [new file with mode: 0644]
libempathy/empathy-tp-chat.c
libempathy/empathy-tp-chat.h
libempathy/empathy-tp-chatroom.c
libempathy/empathy-tp-chatroom.h
libempathy/empathy-tp-contact-list.c
libempathy/empathy-tp-contact-list.h
libempathy/empathy-tp-group.c [new file with mode: 0644]
libempathy/empathy-tp-group.h [new file with mode: 0644]
libempathy/empathy-utils.c [new file with mode: 0644]
libempathy/empathy-utils.h [new file with mode: 0644]
libempathy/gossip-avatar.c [deleted file]
libempathy/gossip-avatar.h [deleted file]
libempathy/gossip-chatroom-manager.c [deleted file]
libempathy/gossip-chatroom-manager.dtd [deleted file]
libempathy/gossip-chatroom-manager.h [deleted file]
libempathy/gossip-chatroom.c [deleted file]
libempathy/gossip-chatroom.h [deleted file]
libempathy/gossip-conf.c [deleted file]
libempathy/gossip-conf.h [deleted file]
libempathy/gossip-contact.c [deleted file]
libempathy/gossip-contact.h [deleted file]
libempathy/gossip-debug.c [deleted file]
libempathy/gossip-debug.h [deleted file]
libempathy/gossip-message.c [deleted file]
libempathy/gossip-message.h [deleted file]
libempathy/gossip-presence.c [deleted file]
libempathy/gossip-presence.h [deleted file]
libempathy/gossip-telepathy-group.c [deleted file]
libempathy/gossip-telepathy-group.h [deleted file]
libempathy/gossip-time.c [deleted file]
libempathy/gossip-time.h [deleted file]
libempathy/gossip-utils.c [deleted file]
libempathy/gossip-utils.h [deleted file]
src/empathy-accounts.c
src/empathy.c

index 92e273f..e3794a2 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2007-06-22 Xavier Claessens  <xclaesse@gmail.com>
+
+       * libempathy/*.[ch]:
+       * libempathy-gtk/*.[ch]:
+       * src/*.[ch]: Rename all filenames starting with "gossip" by "empathy",
+       change namespace of all gossip_*() functions to empathy_*().
+       Fixes bug #444490 (Mario Danic, Xavier Claessens).
+
 2007-06-21 Xavier Claessens  <xclaesse@gmail.com>
 
        * configure.ac: Bump version to 0.9
diff --git a/TODO b/TODO
index a111701..284f8c9 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,19 +1,17 @@
 Things you can do if you want to help:
 
- - Rename all files and functions name to use the empathy namespace. Bug #444490.
  - Porting gossip-account-widget-*.{c,h} from gossip project (Guillaume is already working on IRC widget).
  - UI for inviting a contact in a chatroom.
  - UI for accept/refuse invitation to join a chatroom.
  - UI to send a message directly to a contact.
  - GtkWidget-ify libempathy-gtk. Actually most window/dialog do not inherit from GtkWindow/GtkDialog. Need to create a glade catalog.
- - Filter channels before dispatching them. For example we need a GtkStatusIcon that blink when an event arrives (text/voip/ft channel) and tells the MC to dispatch the channel only when the user clicked the icon. Like in gossip. For that we need a filter DBus API in MC, not yet written, a draft spec is proposed on the telepathy ML.
- - Make use of NetworkManager to set the presence
  - Remove Quit option everywhere, empathy is a session service and shouldn't be leaved.
  - Add sound events
  - Add register capability in GossipAccountsDialog if the profile says it's supported.
  - Write a manual based on gossip's.
  - Testing and Bugfixing.
  - Update translations.
+ - Fix indentation and alignment broken since namespace changed from gossip_ to empathy_
 
 SoC projects:
  - Adding VoIP support based on the patch proposed for gossip.
index 113b37c..5a01c64 100644 (file)
@@ -14,33 +14,33 @@ libempathy_gtk_la_SOURCES =                                                 \
        empathy-status-icon.c                   empathy-status-icon.h           \
        empathy-contact-widget.c                empathy-contact-widget.h        \
        empathy-contact-dialogs.c               empathy-contact-dialogs.h       \
-       gossip-accounts-dialog.c                gossip-accounts-dialog.h        \
-       gossip-account-widget-generic.c         gossip-account-widget-generic.h \
-       gossip-account-widget-jabber.c          gossip-account-widget-jabber.h  \
-       gossip-profile-chooser.c                gossip-profile-chooser.h        \
-       gossip-cell-renderer-expander.c         gossip-cell-renderer-expander.h \
-       gossip-cell-renderer-text.c             gossip-cell-renderer-text.h     \
-       gossip-spell.c                          gossip-spell.h                  \
-       gossip-spell-dialog.c                   gossip-spell-dialog.h           \
-       gossip-contact-groups.c                 gossip-contact-groups.h         \
-       gossip-contact-list-store.c             gossip-contact-list-store.h     \
-       gossip-contact-list-view.c              gossip-contact-list-view.h      \
-       gossip-preferences.c                    gossip-preferences.h            \
-       gossip-theme-manager.c                  gossip-theme-manager.h          \
-       gossip-chat-window.c                    gossip-chat-window.h            \
-       gossip-chat.c                           gossip-chat.h                   \
-       gossip-chat-view.c                      gossip-chat-view.h              \
-       gossip-private-chat.c                   gossip-private-chat.h           \
-       gossip-group-chat.c                     gossip-group-chat.h             \
-       gossip-geometry.c                       gossip-geometry.h               \
-       gossip-status-presets.c                 gossip-status-presets.h         \
-       gossip-presence-chooser.c               gossip-presence-chooser.h       \
-       gossip-about-dialog.c                   gossip-about-dialog.h           \
-       gossip-account-chooser.c                gossip-account-chooser.h        \
-       gossip-new-chatroom-dialog.c            gossip-new-chatroom-dialog.h    \
-       gossip-chatrooms-window.c               gossip-chatrooms-window.h       \
-       gossip-log-window.c                     gossip-log-window.h             \
-       gossip-ui-utils.c                       gossip-ui-utils.h
+       empathy-accounts-dialog.c               empathy-accounts-dialog.h       \
+       empathy-account-widget-generic.c                empathy-account-widget-generic.h        \
+       empathy-account-widget-jabber.c         empathy-account-widget-jabber.h \
+       empathy-profile-chooser.c               empathy-profile-chooser.h       \
+       empathy-cell-renderer-expander.c                empathy-cell-renderer-expander.h        \
+       empathy-cell-renderer-text.c            empathy-cell-renderer-text.h    \
+       empathy-spell.c                         empathy-spell.h                 \
+       empathy-spell-dialog.c                  empathy-spell-dialog.h          \
+       empathy-contact-groups.c                        empathy-contact-groups.h                \
+       empathy-contact-list-store.c            empathy-contact-list-store.h    \
+       empathy-contact-list-view.c             empathy-contact-list-view.h     \
+       empathy-preferences.c                   empathy-preferences.h           \
+       empathy-theme-manager.c                 empathy-theme-manager.h         \
+       empathy-chat-window.c                   empathy-chat-window.h           \
+       empathy-chat.c                          empathy-chat.h                  \
+       empathy-chat-view.c                     empathy-chat-view.h             \
+       empathy-private-chat.c                  empathy-private-chat.h          \
+       empathy-group-chat.c                    empathy-group-chat.h            \
+       empathy-geometry.c                      empathy-geometry.h              \
+       empathy-status-presets.c                        empathy-status-presets.h                \
+       empathy-presence-chooser.c              empathy-presence-chooser.h      \
+       empathy-about-dialog.c                  empathy-about-dialog.h          \
+       empathy-account-chooser.c               empathy-account-chooser.h       \
+       empathy-new-chatroom-dialog.c           empathy-new-chatroom-dialog.h   \
+       empathy-chatrooms-window.c              empathy-chatrooms-window.h      \
+       empathy-log-window.c                    empathy-log-window.h            \
+       empathy-ui-utils.c                      empathy-ui-utils.h
 
 libempathy_gtk_la_LIBADD =                             \
        $(EMPATHY_LIBS)                                 \
@@ -54,21 +54,21 @@ glade_DATA =                                        \
        empathy-status-icon.glade               \
        empathy-contact-widget.glade            \
        empathy-contact-dialogs.glade           \
-       gossip-preferences.glade                \
-       gossip-presence-chooser.glade           \
-       gossip-accounts-dialog.glade            \
-       gossip-account-widget-jabber.glade      \
-       gossip-new-chatroom-dialog.glade        \
-       gossip-group-chat.glade                 \
-       gossip-chatrooms-window.glade           \
-       gossip-spell-dialog.glade               \
-       gossip-log-window.glade                 \
-       gossip-chat.glade
+       empathy-preferences.glade               \
+       empathy-presence-chooser.glade          \
+       empathy-accounts-dialog.glade           \
+       empathy-account-widget-jabber.glade     \
+       empathy-new-chatroom-dialog.glade       \
+       empathy-group-chat.glade                        \
+       empathy-chatrooms-window.glade          \
+       empathy-spell-dialog.glade              \
+       empathy-log-window.glade                        \
+       empathy-chat.glade
 
 dtddir = $(datadir)/empathy
 dtd_DATA =                                     \
-       gossip-status-presets.dtd               \
-       gossip-contact-groups.dtd
+       empathy-status-presets.dtd              \
+       empathy-contact-groups.dtd
 
 
 EXTRA_DIST =                   \
diff --git a/libempathy-gtk/empathy-about-dialog.c b/libempathy-gtk/empathy-about-dialog.c
new file mode 100644 (file)
index 0000000..07d62ab
--- /dev/null
@@ -0,0 +1,113 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2006-2007 Imendio AB
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * 
+ * Authors: Martyn Russell <martyn@imendio.com>
+ *          Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <gtk/gtkaboutdialog.h>
+#include <gtk/gtksizegroup.h>
+#include <glade/glade.h>
+
+#include "empathy-about-dialog.h"
+#include "empathy-ui-utils.h"
+
+#define WEB_SITE "http://live.gnome.org/Empathy"
+
+static void about_dialog_activate_link_cb (GtkAboutDialog  *about,
+                                          const gchar     *link,
+                                          gpointer         data);
+
+static const char *authors[] = {
+       "Mikael Hallendal",
+       "Richard Hult",
+       "Martyn Russell",
+       "Geert-Jan Van den Bogaerde",
+       "Kevin Dougherty",
+       "Eitan Isaacson",
+       "Xavier Claessens",
+       NULL
+};
+
+static const char *documenters[] = {
+       NULL
+};
+
+static const char *artists[] = {
+       "Andreas Nilsson <nisses.mail@home.se>",
+       "Vinicius Depizzol <vdepizzol@gmail.com>",
+       NULL
+};
+
+static const char *license[] = {
+       N_("Empathy 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."),
+       N_("Empathy 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."),
+       N_("You should have received a copy of the GNU General Public License "
+          "along with Empathy; if not, write to the Free Software Foundation, Inc., "
+          "51 Franklin Street, Fifth Floor, Boston, MA 02110-130159 USA")
+};
+
+static void
+about_dialog_activate_link_cb (GtkAboutDialog *about,
+                              const gchar    *link,
+                              gpointer        data)
+{
+       empathy_url_show (link);
+}
+
+void
+empathy_about_dialog_new (GtkWindow *parent)
+{
+       gchar *license_trans;
+
+       gtk_about_dialog_set_url_hook (about_dialog_activate_link_cb, NULL, NULL);
+
+       license_trans = g_strconcat (_(license[0]), "\n\n",
+                                    _(license[1]), "\n\n",
+                                    _(license[2]), "\n\n",
+                                    NULL);
+
+       gtk_show_about_dialog (parent,
+                              "artists", artists,
+                              "authors", authors,
+                              "comments", _("An Instant Messaging client for GNOME"),
+                              "license", license_trans,
+                              "wrap-license", TRUE,
+                              "copyright", "Imendio AB 2002-2007\nCollabora Ltd 2007",
+                              "documenters", documenters,
+                              "logo-icon-name", "empathy",
+                              "translator-credits", _("translator-credits"),
+                              "version", PACKAGE_VERSION,
+                              "website", WEB_SITE,
+                              NULL);
+
+       g_free (license_trans);
+}
+
+
diff --git a/libempathy-gtk/empathy-about-dialog.h b/libempathy-gtk/empathy-about-dialog.h
new file mode 100644 (file)
index 0000000..ad5705e
--- /dev/null
@@ -0,0 +1,34 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2006-2007 Imendio AB
+ *
+ * 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Martyn Russell <martyn@imendio.com>
+ */
+
+#ifndef __EMPATHY_ABOUT_DIALOG_H__
+#define __EMPATHY_ABOUT_DIALOG_H__
+
+#include <gtk/gtkwindow.h>
+
+G_BEGIN_DECLS
+
+void empathy_about_dialog_new (GtkWindow *parent);
+
+G_END_DECLS
+
+#endif /*  __EMPATHY_ABOUT_DIALOG_H__ */
diff --git a/libempathy-gtk/empathy-account-chooser.c b/libempathy-gtk/empathy-account-chooser.c
new file mode 100644 (file)
index 0000000..eb46c52
--- /dev/null
@@ -0,0 +1,637 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2005-2007 Imendio AB
+ *
+ * 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * 
+ * Authors: Martyn Russell <martyn@imendio.com>
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+
+#include <libtelepathy/tp-conn.h>
+#include <libmissioncontrol/mc-account-monitor.h>
+#include <libmissioncontrol/mission-control.h>
+
+#include <libempathy/empathy-utils.h>
+
+#include "empathy-ui-utils.h"
+#include "empathy-account-chooser.h"
+
+#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_ACCOUNT_CHOOSER, EmpathyAccountChooserPriv))
+
+typedef struct {
+       MissionControl   *mc;
+       McAccountMonitor *monitor;
+
+       gboolean          set_active_item;
+       gboolean          can_select_all;
+       gboolean          has_all_option;
+} EmpathyAccountChooserPriv;
+
+typedef struct {
+       EmpathyAccountChooser *chooser;
+       McAccount            *account;
+       gboolean              set;
+} SetAccountData;
+
+enum {
+       COL_ACCOUNT_IMAGE,
+       COL_ACCOUNT_TEXT,
+       COL_ACCOUNT_ENABLED, /* Usually tied to connected state */
+       COL_ACCOUNT_POINTER,
+       COL_ACCOUNT_COUNT
+};
+
+static void     account_chooser_finalize               (GObject                         *object);
+static void     account_chooser_get_property           (GObject                         *object,
+                                                       guint                            param_id,
+                                                       GValue                          *value,
+                                                       GParamSpec                      *pspec);
+static void     account_chooser_set_property           (GObject                         *object,
+                                                       guint                            param_id,
+                                                       const GValue                    *value,
+                                                       GParamSpec                      *pspec);
+static void     account_chooser_setup                  (EmpathyAccountChooser            *chooser);
+static void     account_chooser_account_created_cb     (McAccountMonitor                *monitor,
+                                                       const gchar                     *unique_name,
+                                                       EmpathyAccountChooser            *chooser);
+static void     account_chooser_account_add_foreach    (McAccount                       *account,
+                                                       EmpathyAccountChooser            *chooser);
+static void     account_chooser_account_deleted_cb     (McAccountMonitor                *monitor,
+                                                       const gchar                     *unique_name,
+                                                       EmpathyAccountChooser            *chooser);
+static void     account_chooser_account_remove_foreach (McAccount                       *account,
+                                                       EmpathyAccountChooser            *chooser);
+static void     account_chooser_update_iter            (EmpathyAccountChooser            *chooser,
+                                                       GtkTreeIter                     *iter,
+                                                       McAccount                       *account);
+static void     account_chooser_status_changed_cb      (MissionControl                  *mc,
+                                                       TelepathyConnectionStatus        status,
+                                                       McPresence                       presence,
+                                                       TelepathyConnectionStatusReason  reason,
+                                                       const gchar                     *unique_name,
+                                                       EmpathyAccountChooser            *chooser);
+static gboolean account_chooser_separator_func         (GtkTreeModel                    *model,
+                                                       GtkTreeIter                     *iter,
+                                                       EmpathyAccountChooser            *chooser);
+static gboolean account_chooser_set_account_foreach    (GtkTreeModel                    *model,
+                                                       GtkTreePath                     *path,
+                                                       GtkTreeIter                     *iter,
+                                                       SetAccountData                  *data);
+static gboolean account_chooser_set_enabled_foreach    (GtkTreeModel                    *model,
+                                                       GtkTreePath                     *path,
+                                                       GtkTreeIter                     *iter,
+                                                       EmpathyAccountChooser            *chooser);
+
+enum {
+       PROP_0,
+       PROP_CAN_SELECT_ALL,
+       PROP_HAS_ALL_OPTION,
+};
+
+G_DEFINE_TYPE (EmpathyAccountChooser, empathy_account_chooser, GTK_TYPE_COMBO_BOX);
+
+static void
+empathy_account_chooser_class_init (EmpathyAccountChooserClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       object_class->finalize = account_chooser_finalize;
+       object_class->get_property = account_chooser_get_property;
+       object_class->set_property = account_chooser_set_property;
+
+       g_object_class_install_property (object_class,
+                                        PROP_CAN_SELECT_ALL,
+                                        g_param_spec_boolean ("can-select-all",
+                                                              "Can Select All",
+                                                              "Should the user be able to select offline accounts",
+                                                              FALSE,
+                                                              G_PARAM_READWRITE));
+
+       g_object_class_install_property (object_class,
+                                        PROP_HAS_ALL_OPTION,
+                                        g_param_spec_boolean ("has-all-option",
+                                                              "Has All Option",
+                                                              "Have a separate option in the list to mean ALL accounts",
+                                                              FALSE,
+                                                              G_PARAM_READWRITE));
+
+       g_type_class_add_private (object_class, sizeof (EmpathyAccountChooserPriv));
+}
+
+static void
+empathy_account_chooser_init (EmpathyAccountChooser *chooser)
+{
+}
+
+static void
+account_chooser_finalize (GObject *object)
+{
+       EmpathyAccountChooser     *chooser;
+       EmpathyAccountChooserPriv *priv;
+
+       chooser = EMPATHY_ACCOUNT_CHOOSER (object);
+       priv = GET_PRIV (object);
+
+       g_signal_handlers_disconnect_by_func (priv->monitor,
+                                             account_chooser_account_created_cb,
+                                             chooser);
+       g_signal_handlers_disconnect_by_func (priv->monitor,
+                                             account_chooser_account_deleted_cb,
+                                             chooser);
+       dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc),
+                                       "AccountStatusChanged",
+                                       G_CALLBACK (account_chooser_status_changed_cb),
+                                       chooser);
+       g_object_unref (priv->mc);
+       g_object_unref (priv->monitor);
+
+       G_OBJECT_CLASS (empathy_account_chooser_parent_class)->finalize (object);
+}
+
+static void
+account_chooser_get_property (GObject    *object,
+                             guint       param_id,
+                             GValue     *value,
+                             GParamSpec *pspec)
+{
+       EmpathyAccountChooserPriv *priv;
+
+       priv = GET_PRIV (object);
+
+       switch (param_id) {
+       case PROP_CAN_SELECT_ALL:
+               g_value_set_boolean (value, priv->can_select_all);
+               break;
+       case PROP_HAS_ALL_OPTION:
+               g_value_set_boolean (value, priv->has_all_option);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+               break;
+       };
+}
+
+static void
+account_chooser_set_property (GObject      *object,
+                             guint         param_id,
+                             const GValue *value,
+                             GParamSpec   *pspec)
+{
+       EmpathyAccountChooserPriv *priv;
+
+       priv = GET_PRIV (object);
+
+       switch (param_id) {
+       case PROP_CAN_SELECT_ALL:
+               empathy_account_chooser_set_can_select_all (EMPATHY_ACCOUNT_CHOOSER (object),
+                                                          g_value_get_boolean (value));
+               break;
+       case PROP_HAS_ALL_OPTION:
+               empathy_account_chooser_set_has_all_option (EMPATHY_ACCOUNT_CHOOSER (object),
+                                                          g_value_get_boolean (value));
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+               break;
+       };
+}
+
+GtkWidget *
+empathy_account_chooser_new (void)
+{
+       EmpathyAccountChooserPriv *priv;
+       McAccountMonitor         *monitor;
+       GtkWidget                *chooser;
+
+       monitor = mc_account_monitor_new ();
+       chooser = g_object_new (EMPATHY_TYPE_ACCOUNT_CHOOSER, NULL);
+
+       priv = GET_PRIV (chooser);
+
+       priv->mc = empathy_mission_control_new ();
+       priv->monitor = mc_account_monitor_new ();
+
+       g_signal_connect (priv->monitor, "account-created",
+                         G_CALLBACK (account_chooser_account_created_cb),
+                         chooser);
+       g_signal_connect (priv->monitor, "account-deleted",
+                         G_CALLBACK (account_chooser_account_deleted_cb),
+                         chooser);
+       dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc), "AccountStatusChanged",
+                                    G_CALLBACK (account_chooser_status_changed_cb),
+                                    chooser, NULL);
+
+       account_chooser_setup (EMPATHY_ACCOUNT_CHOOSER (chooser));
+
+       return chooser;
+}
+
+McAccount *
+empathy_account_chooser_get_account (EmpathyAccountChooser *chooser)
+{
+       EmpathyAccountChooserPriv *priv;
+       McAccount                *account;
+       GtkTreeModel             *model;
+       GtkTreeIter               iter;
+
+       g_return_val_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser), NULL);
+
+       priv = GET_PRIV (chooser);
+
+       model = gtk_combo_box_get_model (GTK_COMBO_BOX (chooser));
+       gtk_combo_box_get_active_iter (GTK_COMBO_BOX (chooser), &iter);
+
+       gtk_tree_model_get (model, &iter, COL_ACCOUNT_POINTER, &account, -1);
+
+       return account;
+}
+
+gboolean
+empathy_account_chooser_set_account (EmpathyAccountChooser *chooser,
+                                   McAccount            *account)
+{
+       GtkComboBox    *combobox;
+       GtkTreeModel   *model;
+       GtkTreeIter     iter;
+       SetAccountData  data;
+
+       g_return_val_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser), FALSE);
+
+       combobox = GTK_COMBO_BOX (chooser);
+       model = gtk_combo_box_get_model (combobox);
+       gtk_combo_box_get_active_iter (combobox, &iter);
+
+       data.chooser = chooser;
+       data.account = account;
+
+       gtk_tree_model_foreach (model,
+                               (GtkTreeModelForeachFunc) account_chooser_set_account_foreach,
+                               &data);
+
+       return data.set;
+}
+
+gboolean
+empathy_account_chooser_get_can_select_all (EmpathyAccountChooser *chooser)
+{
+       EmpathyAccountChooserPriv *priv;
+
+       g_return_val_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser), FALSE);
+
+       priv = GET_PRIV (chooser);
+       
+       return priv->can_select_all;
+}
+
+void
+empathy_account_chooser_set_can_select_all (EmpathyAccountChooser *chooser,
+                                          gboolean              can_select_all)
+{
+       EmpathyAccountChooserPriv *priv;
+       GtkComboBox              *combobox;
+       GtkTreeModel             *model;
+
+       g_return_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser));
+
+       priv = GET_PRIV (chooser);
+
+       if (priv->can_select_all == can_select_all) {
+               return;
+       }
+
+       combobox = GTK_COMBO_BOX (chooser);
+       model = gtk_combo_box_get_model (combobox);
+
+       priv->can_select_all = can_select_all;
+
+       gtk_tree_model_foreach (model,
+                               (GtkTreeModelForeachFunc) account_chooser_set_enabled_foreach,
+                               chooser);
+
+       g_object_notify (G_OBJECT (chooser), "can-select-all");
+}
+
+gboolean
+empathy_account_chooser_get_has_all_option (EmpathyAccountChooser *chooser)
+{
+       EmpathyAccountChooserPriv *priv;
+
+       g_return_val_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser), FALSE);
+
+       priv = GET_PRIV (chooser);
+       
+       return priv->has_all_option;
+}
+
+void
+empathy_account_chooser_set_has_all_option (EmpathyAccountChooser *chooser,
+                                          gboolean              has_all_option)
+{
+       EmpathyAccountChooserPriv *priv;
+       GtkComboBox              *combobox;
+       GtkListStore             *store;
+       GtkTreeModel             *model;
+       GtkTreeIter               iter;
+
+       g_return_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser));
+
+       priv = GET_PRIV (chooser);
+
+       if (priv->has_all_option == has_all_option) {
+               return;
+       }
+
+       combobox = GTK_COMBO_BOX (chooser);
+       model = gtk_combo_box_get_model (combobox);
+       store = GTK_LIST_STORE (model);
+
+       priv->has_all_option = has_all_option;
+
+       /*
+        * The first 2 options are the ALL and separator
+        */
+
+       if (has_all_option) {
+               gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (chooser), 
+                                                     (GtkTreeViewRowSeparatorFunc)
+                                                     account_chooser_separator_func,
+                                                     chooser, 
+                                                     NULL);
+
+               gtk_list_store_prepend (store, &iter);
+               gtk_list_store_set (store, &iter, 
+                                   COL_ACCOUNT_TEXT, NULL,
+                                   COL_ACCOUNT_ENABLED, TRUE,
+                                   COL_ACCOUNT_POINTER, NULL,
+                                   -1);
+
+               gtk_list_store_prepend (store, &iter);
+               gtk_list_store_set (store, &iter, 
+                                   COL_ACCOUNT_TEXT, _("All"), 
+                                   COL_ACCOUNT_ENABLED, TRUE,
+                                   COL_ACCOUNT_POINTER, NULL,
+                                   -1);
+       } else {
+               if (gtk_tree_model_get_iter_first (model, &iter)) {
+                       if (gtk_list_store_remove (GTK_LIST_STORE (model), &iter)) {
+                               gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+                       }
+               }
+
+               gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (chooser), 
+                                                     (GtkTreeViewRowSeparatorFunc)
+                                                     NULL,
+                                                     NULL, 
+                                                     NULL);
+       }
+
+       g_object_notify (G_OBJECT (chooser), "has-all-option");
+}
+
+static void
+account_chooser_setup (EmpathyAccountChooser *chooser)
+{
+       EmpathyAccountChooserPriv *priv;
+       GList                    *accounts;
+       GtkListStore             *store;
+       GtkCellRenderer          *renderer;
+       GtkComboBox              *combobox;
+
+       priv = GET_PRIV (chooser);
+
+       /* Set up combo box with new store */
+       combobox = GTK_COMBO_BOX (chooser);
+
+       gtk_cell_layout_clear (GTK_CELL_LAYOUT (combobox));
+
+       store = gtk_list_store_new (COL_ACCOUNT_COUNT,
+                                   G_TYPE_STRING,
+                                   G_TYPE_STRING,    /* Name */
+                                   G_TYPE_BOOLEAN,   /* Enabled */
+                                   MC_TYPE_ACCOUNT);
+
+       gtk_combo_box_set_model (combobox, GTK_TREE_MODEL (store));
+
+       renderer = gtk_cell_renderer_pixbuf_new ();
+       gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox), renderer, FALSE);
+       gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combobox), renderer,
+                                       "icon-name", COL_ACCOUNT_IMAGE,
+                                       "sensitive", COL_ACCOUNT_ENABLED,
+                                       NULL);
+       g_object_set (renderer, "stock-size", GTK_ICON_SIZE_BUTTON, NULL);
+
+       renderer = gtk_cell_renderer_text_new ();
+       gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox), renderer, TRUE);
+       gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combobox), renderer,
+                                       "text", COL_ACCOUNT_TEXT,
+                                       "sensitive", COL_ACCOUNT_ENABLED,
+                                       NULL);
+
+       /* Populate accounts */
+       accounts = mc_accounts_list ();
+       g_list_foreach (accounts,
+                       (GFunc) account_chooser_account_add_foreach,
+                       chooser);
+
+       mc_accounts_list_free (accounts);
+       g_object_unref (store);
+}
+
+static void
+account_chooser_account_created_cb (McAccountMonitor     *monitor,
+                                   const gchar          *unique_name,
+                                   EmpathyAccountChooser *chooser)
+{
+       McAccount *account;
+
+       account = mc_account_lookup (unique_name);
+       account_chooser_account_add_foreach (account, chooser);
+       g_object_unref (account);
+}
+
+static void
+account_chooser_account_add_foreach (McAccount            *account,
+                                    EmpathyAccountChooser *chooser)
+{
+       EmpathyAccountChooserPriv *priv;
+       GtkListStore             *store;
+       GtkComboBox              *combobox;
+       GtkTreeIter               iter;
+
+       priv = GET_PRIV (chooser);
+
+       combobox = GTK_COMBO_BOX (chooser);
+       store = GTK_LIST_STORE (gtk_combo_box_get_model (combobox));
+
+       gtk_list_store_append (store, &iter);
+       account_chooser_update_iter (chooser, &iter, account);
+}
+
+static void
+account_chooser_account_deleted_cb (McAccountMonitor     *monitor,
+                                   const gchar          *unique_name,
+                                   EmpathyAccountChooser *chooser)
+{
+       McAccount *account;
+
+       account = mc_account_lookup (unique_name);
+       account_chooser_account_remove_foreach (account, chooser);
+       g_object_unref (account);
+}
+
+static void
+account_chooser_account_remove_foreach (McAccount            *account,
+                                       EmpathyAccountChooser *chooser)
+{
+       /* Fixme: TODO */
+}
+
+static void
+account_chooser_update_iter (EmpathyAccountChooser *chooser,
+                            GtkTreeIter          *iter,
+                            McAccount            *account)
+{
+       EmpathyAccountChooserPriv *priv;
+       GtkListStore             *store;
+       GtkComboBox              *combobox;
+       TpConn                   *tp_conn;
+       const gchar              *icon_name;
+       gboolean                  is_enabled;
+
+       priv = GET_PRIV (chooser);
+
+       combobox = GTK_COMBO_BOX (chooser);
+       store = GTK_LIST_STORE (gtk_combo_box_get_model (combobox));
+
+       icon_name = empathy_icon_name_from_account (account);
+       tp_conn = mission_control_get_connection (priv->mc, account, NULL);
+       is_enabled = (tp_conn != NULL || priv->can_select_all);
+
+       if (tp_conn) {
+               g_object_unref (tp_conn);
+       }
+
+       gtk_list_store_set (store, iter,
+                           COL_ACCOUNT_IMAGE, icon_name,
+                           COL_ACCOUNT_TEXT, mc_account_get_display_name (account),
+                           COL_ACCOUNT_ENABLED, is_enabled,
+                           COL_ACCOUNT_POINTER, account,
+                           -1);
+
+       /* set first connected account as active account */
+       if (priv->set_active_item == FALSE && is_enabled) {
+               priv->set_active_item = TRUE;
+               gtk_combo_box_set_active_iter (combobox, iter);
+       }
+}
+
+static void
+account_chooser_status_changed_cb (MissionControl                  *mc,
+                                  TelepathyConnectionStatus        status,
+                                  McPresence                       presence,
+                                  TelepathyConnectionStatusReason  reason,
+                                  const gchar                     *unique_name,
+                                  EmpathyAccountChooser            *chooser)
+{
+       /* FIXME: implement */
+}
+
+static gboolean
+account_chooser_separator_func (GtkTreeModel         *model,
+                               GtkTreeIter          *iter,
+                               EmpathyAccountChooser *chooser)
+{
+       EmpathyAccountChooserPriv *priv;
+       gchar                    *text;
+       gboolean                  is_separator;
+
+       priv = GET_PRIV (chooser);
+       
+       if (!priv->has_all_option) {
+               return FALSE;
+       }
+       
+       gtk_tree_model_get (model, iter, COL_ACCOUNT_TEXT, &text, -1);
+       is_separator = text == NULL;
+       g_free (text);
+
+       return is_separator;
+}
+
+static gboolean
+account_chooser_set_account_foreach (GtkTreeModel   *model,
+                                    GtkTreePath    *path,
+                                    GtkTreeIter    *iter,
+                                    SetAccountData *data)
+{
+       McAccount *account;
+       gboolean   equal;
+
+       gtk_tree_model_get (model, iter, COL_ACCOUNT_POINTER, &account, -1);
+
+       /* Special case so we can make it possible to select the All option */
+       if (!data->account && !account) {
+               equal = TRUE;
+       }
+       else if ((data->account && !account) || (!data->account && account)) {
+               equal = FALSE;
+       } else {
+               equal = empathy_account_equal (data->account, account);
+               g_object_unref (account);
+       }
+
+       if (equal) {
+               GtkComboBox *combobox;
+
+               combobox = GTK_COMBO_BOX (data->chooser);
+               gtk_combo_box_set_active_iter (combobox, iter);
+
+               data->set = TRUE;
+       }
+
+       return equal;
+}
+
+static gboolean
+account_chooser_set_enabled_foreach (GtkTreeModel         *model,
+                                    GtkTreePath          *path,
+                                    GtkTreeIter          *iter,
+                                    EmpathyAccountChooser *chooser)
+{
+       EmpathyAccountChooserPriv *priv;
+       McAccount                *account;
+
+       priv = GET_PRIV (chooser);
+
+       gtk_tree_model_get (model, iter, COL_ACCOUNT_POINTER, &account, -1);
+       if (!account) {
+               return FALSE;
+       }
+
+       account_chooser_update_iter (chooser, iter, account);
+       g_object_unref (account);
+
+       return FALSE;
+}
+
diff --git a/libempathy-gtk/empathy-account-chooser.h b/libempathy-gtk/empathy-account-chooser.h
new file mode 100644 (file)
index 0000000..8d9cb65
--- /dev/null
@@ -0,0 +1,66 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2005-2007 Imendio AB
+ *
+ * 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * 
+ * Authors: Martyn Russell <martyn@imendio.com>
+ */
+
+#ifndef __EMPATHY_ACCOUNT_CHOOSER_H__
+#define __EMPATHY_ACCOUNT_CHOOSER_H__
+
+#include <gtk/gtkcombobox.h>
+
+#include <libmissioncontrol/mc-account.h>
+
+G_BEGIN_DECLS
+
+#define EMPATHY_TYPE_ACCOUNT_CHOOSER (empathy_account_chooser_get_type ())
+#define EMPATHY_ACCOUNT_CHOOSER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_ACCOUNT_CHOOSER, EmpathyAccountChooser))
+#define EMPATHY_ACCOUNT_CHOOSER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EMPATHY_TYPE_ACCOUNT_CHOOSER, EmpathyAccountChooserClass))
+#define EMPATHY_IS_ACCOUNT_CHOOSER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_ACCOUNT_CHOOSER))
+#define EMPATHY_IS_ACCOUNT_CHOOSER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_ACCOUNT_CHOOSER))
+#define EMPATHY_ACCOUNT_CHOOSER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_ACCOUNT_CHOOSER, EmpathyAccountChooserClass))
+
+typedef struct _EmpathyAccountChooser      EmpathyAccountChooser;
+typedef struct _EmpathyAccountChooserClass EmpathyAccountChooserClass;
+
+struct _EmpathyAccountChooser {
+       GtkComboBox parent;
+};
+
+struct _EmpathyAccountChooserClass {
+       GtkComboBoxClass parent_class;
+};
+
+GType          empathy_account_chooser_get_type           (void) G_GNUC_CONST;
+GtkWidget *    empathy_account_chooser_new                (void);
+McAccount *    empathy_account_chooser_get_account        (EmpathyAccountChooser *chooser);
+gboolean       empathy_account_chooser_set_account        (EmpathyAccountChooser *chooser,
+                                                         McAccount            *account);
+gboolean       empathy_account_chooser_get_can_select_all (EmpathyAccountChooser *chooser);
+
+void           empathy_account_chooser_set_can_select_all (EmpathyAccountChooser *chooser,
+                                                         gboolean              can_select_all);
+gboolean       empathy_account_chooser_get_has_all_option (EmpathyAccountChooser *chooser);
+void           empathy_account_chooser_set_has_all_option (EmpathyAccountChooser *chooser,
+                                                         gboolean              has_all_option);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_ACCOUNT_CHOOSER_H__ */
+
diff --git a/libempathy-gtk/empathy-account-widget-generic.c b/libempathy-gtk/empathy-account-widget-generic.c
new file mode 100644 (file)
index 0000000..4f9ea03
--- /dev/null
@@ -0,0 +1,310 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2006-2007 Imendio AB
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * 
+ * Authors: Xavier Claessens <xclaesse@gmail.com>
+ *          Martyn Russell <martyn@imendio.com>
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+
+#include <libmissioncontrol/mc-account.h>
+#include <libmissioncontrol/mc-protocol.h>
+
+#include <libempathy-gtk/empathy-ui-utils.h>
+
+#include "empathy-account-widget-generic.h"
+
+typedef struct {
+       McAccount     *account;
+
+       GtkWidget     *sw;
+       GtkWidget     *table_settings;
+       GtkSizeGroup  *size_group;
+
+       guint          n_rows;
+} EmpathyAccountWidgetGeneric;
+
+static gboolean account_widget_generic_entry_focus_cb         (GtkWidget                  *widget,
+                                                              GdkEventFocus              *event,
+                                                              EmpathyAccountWidgetGeneric *settings);
+static void     account_widget_generic_int_changed_cb         (GtkWidget                  *widget,
+                                                              EmpathyAccountWidgetGeneric *settings);
+static void     account_widget_generic_checkbutton_toggled_cb (GtkWidget                  *widget,
+                                                              EmpathyAccountWidgetGeneric *settings);
+static gchar *  account_widget_generic_format_param_name      (const gchar                *param_name);
+static void     account_widget_generic_setup_foreach          (McProtocolParam            *param,
+                                                              EmpathyAccountWidgetGeneric *settings);
+static void     account_widget_generic_destroy_cb             (GtkWidget                  *widget,
+                                                              EmpathyAccountWidgetGeneric *settings);
+
+static gboolean 
+account_widget_generic_entry_focus_cb (GtkWidget                  *widget,
+                                      GdkEventFocus              *event,
+                                      EmpathyAccountWidgetGeneric *settings)
+{
+       const gchar *str;
+       const gchar *param_name;
+
+       str = gtk_entry_get_text (GTK_ENTRY (widget));
+       param_name = g_object_get_data (G_OBJECT (widget), "param_name");
+
+       mc_account_set_param_string (settings->account, param_name, str);
+
+       return FALSE;
+}
+
+static void
+account_widget_generic_int_changed_cb (GtkWidget                  *widget,
+                                      EmpathyAccountWidgetGeneric *settings)
+{
+       const gchar *param_name;
+       gint         value;
+
+       value = gtk_spin_button_get_value (GTK_SPIN_BUTTON (widget));
+       param_name = g_object_get_data (G_OBJECT (widget), "param_name");
+
+       mc_account_set_param_int (settings->account, param_name, value);
+}
+
+static void  
+account_widget_generic_checkbutton_toggled_cb (GtkWidget                  *widget,
+                                              EmpathyAccountWidgetGeneric *settings)
+{
+       gboolean     active;
+       const gchar *param_name;
+
+       active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+       param_name = g_object_get_data (G_OBJECT (widget), "param_name");
+
+       mc_account_set_param_boolean (settings->account, param_name, active);
+}
+
+static gchar *
+account_widget_generic_format_param_name (const gchar *param_name)
+{
+       gchar *str;
+       gchar *p;
+
+       str = g_strdup (param_name);
+       
+       if (str && g_ascii_isalpha (str[0])) {
+               str[0] = g_ascii_toupper (str[0]);
+       }
+       
+       while ((p = strchr (str, '-')) != NULL) {
+               if (p[1] != '\0' && g_ascii_isalpha (p[1])) {
+                       p[0] = ' ';
+                       p[1] = g_ascii_toupper (p[1]);
+               }
+
+               p++;
+       }
+       
+       return str;
+}
+
+static void
+account_widget_generic_setup_foreach (McProtocolParam            *param,
+                                     EmpathyAccountWidgetGeneric *settings)
+{
+       GtkWidget *widget;
+       gchar     *param_name_formatted;
+
+       param_name_formatted = account_widget_generic_format_param_name (param->name);
+
+       gtk_table_resize (GTK_TABLE (settings->table_settings),
+                         ++settings->n_rows,
+                         2);
+
+       if (param->signature[0] == 's') {
+               gchar *str = NULL;
+
+               str = g_strdup_printf (_("%s:"), param_name_formatted);
+               widget = gtk_label_new (str);
+               g_free (str);
+
+               gtk_size_group_add_widget (settings->size_group, widget);
+               gtk_table_attach (GTK_TABLE (settings->table_settings),
+                                 widget,
+                                 0, 1,
+                                 settings->n_rows - 1, settings->n_rows,
+                                 GTK_FILL, 0,
+                                 0, 0);
+
+               str = NULL;
+               widget = gtk_entry_new ();
+               mc_account_get_param_string (settings->account,
+                                            param->name,
+                                            &str);
+               if (str) {
+                       gtk_entry_set_text (GTK_ENTRY (widget), str);
+                       g_free (str);
+               }
+
+               if (strstr (param->name, "password")) {
+                       gtk_entry_set_visibility (GTK_ENTRY (widget), FALSE);
+               }
+
+               g_signal_connect (widget, "focus-out-event",
+                                 G_CALLBACK (account_widget_generic_entry_focus_cb),
+                                 settings);
+
+               gtk_table_attach (GTK_TABLE (settings->table_settings),
+                                 widget,
+                                 1, 2,
+                                 settings->n_rows - 1, settings->n_rows,
+                                 GTK_FILL | GTK_EXPAND, 0,
+                                 0, 0);
+       }
+       else if (param->signature[0] == 'q' ||
+                param->signature[0] == 'n') {
+               gchar *str = NULL;
+               gint   value = 0;
+
+               str = g_strdup_printf (_("%s:"), param_name_formatted);
+               widget = gtk_label_new (str);
+               g_free (str);
+
+               gtk_size_group_add_widget (settings->size_group, widget);
+               gtk_table_attach (GTK_TABLE (settings->table_settings),
+                                 widget,
+                                 0, 1,
+                                 settings->n_rows - 1, settings->n_rows,
+                                 GTK_FILL, 0,
+                                 0, 0);
+
+               widget = gtk_spin_button_new_with_range (0, G_MAXINT, 1);
+               mc_account_get_param_int (settings->account,
+                                         param->name,
+                                         &value);
+               gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
+
+               g_signal_connect (widget, "value-changed",
+                                 G_CALLBACK (account_widget_generic_int_changed_cb),
+                                 settings);
+
+               gtk_table_attach (GTK_TABLE (settings->table_settings),
+                                 widget,
+                                 1, 2,
+                                 settings->n_rows - 1, settings->n_rows,
+                                 GTK_FILL | GTK_EXPAND, 0,
+                                 0, 0);
+       }
+       else if (param->signature[0] == 'b') {
+               gboolean value = FALSE;
+
+               mc_account_get_param_boolean (settings->account,
+                                             param->name,
+                                             &value);
+
+               widget = gtk_check_button_new_with_label (param_name_formatted);
+               gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), value);
+
+               g_signal_connect (widget, "toggled",
+                                 G_CALLBACK (account_widget_generic_checkbutton_toggled_cb),
+                                 settings);
+
+               gtk_table_attach (GTK_TABLE (settings->table_settings),
+                                 widget,
+                                 0, 2,
+                                 settings->n_rows - 1, settings->n_rows,
+                                 GTK_FILL | GTK_EXPAND, 0,
+                                 0, 0);
+       } else {
+               g_assert_not_reached ();
+       }
+
+       g_free (param_name_formatted);
+
+       g_object_set_data_full (G_OBJECT (widget), "param_name", 
+                               g_strdup (param->name), g_free);
+}
+
+static void
+accounts_widget_generic_setup (EmpathyAccountWidgetGeneric *settings)
+{
+       McProtocol *protocol;
+       McProfile  *profile;
+       GSList     *params;
+
+       profile = mc_account_get_profile (settings->account);
+       protocol = mc_profile_get_protocol (profile);
+       params = mc_protocol_get_params (protocol);
+
+       g_slist_foreach (params,
+                        (GFunc) account_widget_generic_setup_foreach,
+                        settings);
+
+       g_slist_free (params);
+}
+
+static void
+account_widget_generic_destroy_cb (GtkWidget                  *widget,
+                                  EmpathyAccountWidgetGeneric *settings)
+{
+       g_object_unref (settings->account);
+       g_object_unref (settings->size_group);
+
+       g_free (settings);
+}
+
+GtkWidget *
+empathy_account_widget_generic_new (McAccount *account,
+                                  GtkWidget *label_name)
+{
+       EmpathyAccountWidgetGeneric *settings;
+
+       g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
+       g_return_val_if_fail (GTK_IS_WIDGET (label_name), NULL);
+
+       settings = g_new0 (EmpathyAccountWidgetGeneric, 1);
+
+       settings->account = g_object_ref (account);
+
+       settings->table_settings = gtk_table_new (0, 2, FALSE);
+       gtk_table_set_row_spacings (GTK_TABLE (settings->table_settings), 6);
+       gtk_table_set_col_spacings (GTK_TABLE (settings->table_settings), 6);
+       settings->sw = gtk_scrolled_window_new (NULL, NULL);
+       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (settings->sw),
+                                       GTK_POLICY_AUTOMATIC,
+                                       GTK_POLICY_AUTOMATIC);
+       gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (settings->sw),
+                                              settings->table_settings);
+
+       settings->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+       if (label_name) {
+               gtk_size_group_add_widget (settings->size_group, label_name);
+       }
+       
+       accounts_widget_generic_setup (settings);
+
+       g_signal_connect (settings->sw, "destroy",
+                         G_CALLBACK (account_widget_generic_destroy_cb),
+                         settings);
+
+       gtk_widget_show_all (settings->sw);
+
+       return settings->sw;
+}
diff --git a/libempathy-gtk/empathy-account-widget-generic.h b/libempathy-gtk/empathy-account-widget-generic.h
new file mode 100644 (file)
index 0000000..e26c72e
--- /dev/null
@@ -0,0 +1,39 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2006-2007 Imendio AB
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * 
+ * Authors: Xavier Claessens <xclaesse@gmail.com>
+ *          Martyn Russell <martyn@imendio.com>
+ */
+
+#ifndef __EMPATHY_ACCOUNT_WIDGET_GENERIC_H__
+#define __EMPATHY_ACCOUNT_WIDGET_GENERIC_H__
+
+#include <gtk/gtk.h>
+
+#include <libmissioncontrol/mc-account.h>
+
+G_BEGIN_DECLS
+
+GtkWidget *empathy_account_widget_generic_new (McAccount *account,
+                                             GtkWidget *label_name);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_ACCOUNT_WIDGET_GENERIC_H__ */
diff --git a/libempathy-gtk/empathy-account-widget-jabber.c b/libempathy-gtk/empathy-account-widget-jabber.c
new file mode 100644 (file)
index 0000000..2e5a487
--- /dev/null
@@ -0,0 +1,281 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * 
+ * Authors: Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include "config.h"
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+
+#include <libmissioncontrol/mc-profile.h>
+
+#include <libempathy/empathy-utils.h>
+
+#include "empathy-account-widget-jabber.h"
+#include "empathy-ui-utils.h"
+
+#define PORT_WITHOUT_SSL 5222
+#define PORT_WITH_SSL 5223
+
+typedef struct {
+       McAccount *account;
+
+       GtkWidget *vbox_settings;
+       GtkWidget *button_forget;
+       GtkWidget *entry_id;
+       GtkWidget *entry_password;
+       GtkWidget *entry_resource;
+       GtkWidget *entry_server;
+       GtkWidget *spinbutton_port;
+       GtkWidget *checkbutton_ssl;
+} EmpathyAccountWidgetJabber;
+
+static gboolean account_widget_jabber_entry_focus_cb           (GtkWidget                 *widget,
+                                                               GdkEventFocus             *event,
+                                                               EmpathyAccountWidgetJabber *settings);
+static void     account_widget_jabber_entry_changed_cb         (GtkWidget                 *widget,
+                                                               EmpathyAccountWidgetJabber *settings);
+static void     account_widget_jabber_checkbutton_toggled_cb   (GtkWidget                 *widget,
+                                                               EmpathyAccountWidgetJabber *settings);
+static void     account_widget_jabber_value_changed_cb         (GtkWidget                 *spinbutton,
+                                                               EmpathyAccountWidgetJabber *settings);
+static void     account_widget_jabber_button_forget_clicked_cb (GtkWidget                 *button,
+                                                               EmpathyAccountWidgetJabber *settings);
+static void     account_widget_jabber_destroy_cb               (GtkWidget                 *widget,
+                                                               EmpathyAccountWidgetJabber *settings);
+static void     account_widget_jabber_setup                    (EmpathyAccountWidgetJabber *settings);
+
+static gboolean
+account_widget_jabber_entry_focus_cb (GtkWidget                 *widget,
+                                     GdkEventFocus             *event,
+                                     EmpathyAccountWidgetJabber *settings)
+{
+       const gchar *param;
+       const gchar *str;
+
+       if (widget == settings->entry_password) {
+               param = "password";
+       }
+       else if (widget == settings->entry_resource) {
+               param = "resource";
+       }
+       else if (widget == settings->entry_server) {
+               param = "server";
+       }
+       else if (widget == settings->entry_id) {
+               param = "account";
+       } else {
+               return FALSE;
+       }
+
+       str = gtk_entry_get_text (GTK_ENTRY (widget));
+       if (G_STR_EMPTY (str)) {
+               gchar *value = NULL;
+
+               mc_account_get_param_string (settings->account, param, &value);
+               gtk_entry_set_text (GTK_ENTRY (widget), value ? value : "");
+               g_free (value);
+       } else {
+               mc_account_set_param_string (settings->account, param, str);
+       }
+
+       return FALSE;
+}
+
+static void
+account_widget_jabber_entry_changed_cb (GtkWidget                 *widget,
+                                       EmpathyAccountWidgetJabber *settings)
+{
+       if (widget == settings->entry_password) {
+               const gchar *str;
+
+               str = gtk_entry_get_text (GTK_ENTRY (widget));
+               gtk_widget_set_sensitive (settings->button_forget, !G_STR_EMPTY (str));
+       }
+}
+
+static void  
+account_widget_jabber_checkbutton_toggled_cb (GtkWidget                 *widget,
+                                             EmpathyAccountWidgetJabber *settings)
+{
+       if (widget == settings->checkbutton_ssl) {
+               gint     port = 0;
+               gboolean old_ssl;
+
+               mc_account_get_param_int (settings->account, "port", &port);
+               old_ssl = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+
+               if (old_ssl) {
+                       if (port == PORT_WITHOUT_SSL) {
+                               port = PORT_WITH_SSL;
+                       }
+               } else {
+                       if (port == PORT_WITH_SSL) {
+                               port = PORT_WITHOUT_SSL;
+                       }
+               }
+               
+               mc_account_set_param_int (settings->account, "port", port);
+               mc_account_set_param_boolean (settings->account, "old-ssl", old_ssl);
+               gtk_spin_button_set_value (GTK_SPIN_BUTTON (settings->spinbutton_port), port);
+       }
+}
+
+static void
+account_widget_jabber_value_changed_cb (GtkWidget                 *spinbutton,
+                                       EmpathyAccountWidgetJabber *settings)
+{
+       if (spinbutton == settings->spinbutton_port) {
+               gdouble value;
+
+               value = gtk_spin_button_get_value (GTK_SPIN_BUTTON (spinbutton));
+               mc_account_set_param_int (settings->account, "port", (gint) value);
+       }
+}
+
+static void
+account_widget_jabber_button_forget_clicked_cb (GtkWidget                 *button,
+                                               EmpathyAccountWidgetJabber *settings)
+{
+       mc_account_set_param_string (settings->account, "password", "");
+       gtk_entry_set_text (GTK_ENTRY (settings->entry_password), "");
+}
+
+static void
+account_widget_jabber_destroy_cb (GtkWidget                 *widget,
+                                 EmpathyAccountWidgetJabber *settings)
+{
+       g_object_unref (settings->account);
+       g_free (settings);
+}
+
+static void
+account_widget_jabber_setup (EmpathyAccountWidgetJabber *settings)
+{
+       gint      port = 0;
+       gchar    *id = NULL;
+       gchar    *resource = NULL;
+       gchar    *server = NULL;
+       gchar    *password = NULL;
+       gboolean  old_ssl = FALSE;
+
+       mc_account_get_param_int (settings->account, "port", &port);
+       mc_account_get_param_string (settings->account, "account", &id);
+       mc_account_get_param_string (settings->account, "resource", &resource);
+       mc_account_get_param_string (settings->account, "server", &server);
+       mc_account_get_param_string (settings->account, "password", &password);
+       mc_account_get_param_boolean (settings->account, "old-ssl", &old_ssl);
+
+       if (!id) {
+               McProfile   *profile;
+               const gchar *server;
+
+               profile = mc_account_get_profile (settings->account);
+               server = mc_profile_get_default_account_domain (profile);
+               if (server) {
+                       id = g_strconcat ("user@", server, NULL);
+               }
+               g_object_unref (profile);
+       }
+
+       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (settings->checkbutton_ssl), old_ssl);
+       gtk_entry_set_text (GTK_ENTRY (settings->entry_id), id ? id : "");
+       gtk_entry_set_text (GTK_ENTRY (settings->entry_password), password ? password : "");
+       gtk_entry_set_text (GTK_ENTRY (settings->entry_resource), resource ? resource : "");
+       gtk_entry_set_text (GTK_ENTRY (settings->entry_server), server ? server : "");
+       gtk_spin_button_set_value (GTK_SPIN_BUTTON (settings->spinbutton_port), port);
+
+       gtk_widget_set_sensitive (settings->button_forget, !G_STR_EMPTY (password));
+
+       g_free (id);
+       g_free (resource);
+       g_free (server);
+       g_free (password);
+}
+
+GtkWidget *
+empathy_account_widget_jabber_new (McAccount *account)
+{
+       EmpathyAccountWidgetJabber *settings;
+       GladeXML                  *glade;
+       GtkSizeGroup              *size_group;
+       GtkWidget                 *label_id, *label_password;
+       GtkWidget                 *label_server, *label_resource, *label_port; 
+
+       settings = g_new0 (EmpathyAccountWidgetJabber, 1);
+       settings->account = g_object_ref (account);
+
+       glade = empathy_glade_get_file ("empathy-account-widget-jabber.glade",
+                                      "vbox_jabber_settings",
+                                      NULL,
+                                      "vbox_jabber_settings", &settings->vbox_settings,
+                                      "button_forget", &settings->button_forget,
+                                      "label_id", &label_id,
+                                      "label_password", &label_password,
+                                      "label_resource", &label_resource,
+                                      "label_server", &label_server,
+                                      "label_port", &label_port,
+                                      "entry_id", &settings->entry_id,
+                                      "entry_password", &settings->entry_password,
+                                      "entry_resource", &settings->entry_resource,
+                                      "entry_server", &settings->entry_server,
+                                      "spinbutton_port", &settings->spinbutton_port,
+                                      "checkbutton_ssl", &settings->checkbutton_ssl,
+                                      NULL);
+
+       account_widget_jabber_setup (settings);
+
+       empathy_glade_connect (glade, 
+                             settings,
+                             "vbox_jabber_settings", "destroy", account_widget_jabber_destroy_cb,
+                             "button_forget", "clicked", account_widget_jabber_button_forget_clicked_cb,
+                             "entry_password", "changed", account_widget_jabber_entry_changed_cb,
+                             "spinbutton_port", "value-changed", account_widget_jabber_value_changed_cb,
+                             "entry_id", "focus-out-event", account_widget_jabber_entry_focus_cb,
+                             "entry_password", "focus-out-event", account_widget_jabber_entry_focus_cb,
+                             "entry_resource", "focus-out-event", account_widget_jabber_entry_focus_cb,
+                             "entry_server", "focus-out-event", account_widget_jabber_entry_focus_cb,
+                             "checkbutton_ssl", "toggled", account_widget_jabber_checkbutton_toggled_cb,
+                             NULL);
+
+       g_object_unref (glade);
+
+       /* Set up remaining widgets */
+       size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+
+       gtk_size_group_add_widget (size_group, label_id);
+       gtk_size_group_add_widget (size_group, label_password);
+       gtk_size_group_add_widget (size_group, label_resource);
+       gtk_size_group_add_widget (size_group, label_server);
+       gtk_size_group_add_widget (size_group, label_port);
+
+       g_object_unref (size_group);
+
+       gtk_widget_show (settings->vbox_settings);
+
+       return settings->vbox_settings;
+}
+
diff --git a/libempathy-gtk/empathy-account-widget-jabber.glade b/libempathy-gtk/empathy-account-widget-jabber.glade
new file mode 100644 (file)
index 0000000..12eec75
--- /dev/null
@@ -0,0 +1,335 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkWindow" id="account_jabber_settings">
+  <property name="visible">True</property>
+  <property name="title" translatable="yes">jabber account settings</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_NONE</property>
+  <property name="modal">False</property>
+  <property name="resizable">False</property>
+  <property name="destroy_with_parent">False</property>
+  <property name="decorated">True</property>
+  <property name="skip_taskbar_hint">False</property>
+  <property name="skip_pager_hint">False</property>
+  <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+  <property name="focus_on_map">True</property>
+  <property name="urgency_hint">False</property>
+
+  <child>
+    <widget class="GtkTable" id="vbox_jabber_settings">
+      <property name="n_rows">6</property>
+      <property name="n_columns">3</property>
+      <property name="homogeneous">False</property>
+      <property name="row_spacing">6</property>
+      <property name="column_spacing">12</property>
+
+      <child>
+       <widget class="GtkLabel" id="label_id">
+         <property name="visible">True</property>
+         <property name="label" translatable="yes">Login I_D:</property>
+         <property name="use_underline">True</property>
+         <property name="use_markup">False</property>
+         <property name="justify">GTK_JUSTIFY_LEFT</property>
+         <property name="wrap">False</property>
+         <property name="selectable">False</property>
+         <property name="xalign">0</property>
+         <property name="yalign">0.5</property>
+         <property name="xpad">0</property>
+         <property name="ypad">0</property>
+         <property name="mnemonic_widget">entry_id</property>
+         <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+         <property name="width_chars">-1</property>
+         <property name="single_line_mode">False</property>
+         <property name="angle">0</property>
+       </widget>
+       <packing>
+         <property name="left_attach">0</property>
+         <property name="right_attach">1</property>
+         <property name="top_attach">0</property>
+         <property name="bottom_attach">1</property>
+         <property name="x_options">fill</property>
+         <property name="y_options"></property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkLabel" id="label_password">
+         <property name="visible">True</property>
+         <property name="label" translatable="yes">Pass_word:</property>
+         <property name="use_underline">True</property>
+         <property name="use_markup">False</property>
+         <property name="justify">GTK_JUSTIFY_LEFT</property>
+         <property name="wrap">False</property>
+         <property name="selectable">False</property>
+         <property name="xalign">0</property>
+         <property name="yalign">0.5</property>
+         <property name="xpad">0</property>
+         <property name="ypad">0</property>
+         <property name="mnemonic_widget">entry_password</property>
+         <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+         <property name="width_chars">-1</property>
+         <property name="single_line_mode">False</property>
+         <property name="angle">0</property>
+       </widget>
+       <packing>
+         <property name="left_attach">0</property>
+         <property name="right_attach">1</property>
+         <property name="top_attach">1</property>
+         <property name="bottom_attach">2</property>
+         <property name="x_options">fill</property>
+         <property name="y_options"></property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkLabel" id="label_resource">
+         <property name="visible">True</property>
+         <property name="label" translatable="yes">Reso_urce:</property>
+         <property name="use_underline">True</property>
+         <property name="use_markup">False</property>
+         <property name="justify">GTK_JUSTIFY_LEFT</property>
+         <property name="wrap">False</property>
+         <property name="selectable">False</property>
+         <property name="xalign">0</property>
+         <property name="yalign">0.5</property>
+         <property name="xpad">0</property>
+         <property name="ypad">0</property>
+         <property name="mnemonic_widget">entry_resource</property>
+         <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+         <property name="width_chars">-1</property>
+         <property name="single_line_mode">False</property>
+         <property name="angle">0</property>
+       </widget>
+       <packing>
+         <property name="left_attach">0</property>
+         <property name="right_attach">1</property>
+         <property name="top_attach">2</property>
+         <property name="bottom_attach">3</property>
+         <property name="x_options">fill</property>
+         <property name="y_options"></property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkLabel" id="label_server">
+         <property name="visible">True</property>
+         <property name="label" translatable="yes">_Server:</property>
+         <property name="use_underline">True</property>
+         <property name="use_markup">False</property>
+         <property name="justify">GTK_JUSTIFY_LEFT</property>
+         <property name="wrap">False</property>
+         <property name="selectable">False</property>
+         <property name="xalign">0</property>
+         <property name="yalign">0.5</property>
+         <property name="xpad">0</property>
+         <property name="ypad">0</property>
+         <property name="mnemonic_widget">entry_server</property>
+         <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+         <property name="width_chars">-1</property>
+         <property name="single_line_mode">False</property>
+         <property name="angle">0</property>
+       </widget>
+       <packing>
+         <property name="left_attach">0</property>
+         <property name="right_attach">1</property>
+         <property name="top_attach">3</property>
+         <property name="bottom_attach">4</property>
+         <property name="x_options">fill</property>
+         <property name="y_options"></property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkLabel" id="label_port">
+         <property name="visible">True</property>
+         <property name="label" translatable="yes">_Port:</property>
+         <property name="use_underline">True</property>
+         <property name="use_markup">False</property>
+         <property name="justify">GTK_JUSTIFY_LEFT</property>
+         <property name="wrap">False</property>
+         <property name="selectable">False</property>
+         <property name="xalign">0</property>
+         <property name="yalign">0.5</property>
+         <property name="xpad">0</property>
+         <property name="ypad">0</property>
+         <property name="mnemonic_widget">spinbutton_port</property>
+         <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+         <property name="width_chars">-1</property>
+         <property name="single_line_mode">False</property>
+         <property name="angle">0</property>
+       </widget>
+       <packing>
+         <property name="left_attach">0</property>
+         <property name="right_attach">1</property>
+         <property name="top_attach">4</property>
+         <property name="bottom_attach">5</property>
+         <property name="x_options">fill</property>
+         <property name="y_options"></property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkEntry" id="entry_resource">
+         <property name="visible">True</property>
+         <property name="can_focus">True</property>
+         <property name="editable">True</property>
+         <property name="visibility">True</property>
+         <property name="max_length">0</property>
+         <property name="text" translatable="yes"></property>
+         <property name="has_frame">True</property>
+         <property name="invisible_char">*</property>
+         <property name="activates_default">False</property>
+       </widget>
+       <packing>
+         <property name="left_attach">1</property>
+         <property name="right_attach">3</property>
+         <property name="top_attach">2</property>
+         <property name="bottom_attach">3</property>
+         <property name="y_options"></property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkEntry" id="entry_server">
+         <property name="visible">True</property>
+         <property name="can_focus">True</property>
+         <property name="editable">True</property>
+         <property name="visibility">True</property>
+         <property name="max_length">0</property>
+         <property name="text" translatable="yes"></property>
+         <property name="has_frame">True</property>
+         <property name="invisible_char">*</property>
+         <property name="activates_default">False</property>
+       </widget>
+       <packing>
+         <property name="left_attach">1</property>
+         <property name="right_attach">3</property>
+         <property name="top_attach">3</property>
+         <property name="bottom_attach">4</property>
+         <property name="y_options"></property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkCheckButton" id="checkbutton_ssl">
+         <property name="visible">True</property>
+         <property name="can_focus">True</property>
+         <property name="label" translatable="yes">Use encryption (SS_L)</property>
+         <property name="use_underline">True</property>
+         <property name="relief">GTK_RELIEF_NORMAL</property>
+         <property name="focus_on_click">True</property>
+         <property name="active">False</property>
+         <property name="inconsistent">False</property>
+         <property name="draw_indicator">True</property>
+       </widget>
+       <packing>
+         <property name="left_attach">0</property>
+         <property name="right_attach">3</property>
+         <property name="top_attach">5</property>
+         <property name="bottom_attach">6</property>
+         <property name="x_options">fill</property>
+         <property name="y_options"></property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkSpinButton" id="spinbutton_port">
+         <property name="visible">True</property>
+         <property name="can_focus">True</property>
+         <property name="climb_rate">1</property>
+         <property name="digits">0</property>
+         <property name="numeric">True</property>
+         <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+         <property name="snap_to_ticks">False</property>
+         <property name="wrap">False</property>
+         <property name="adjustment">5222 0 65556 1 10 10</property>
+       </widget>
+       <packing>
+         <property name="left_attach">1</property>
+         <property name="right_attach">3</property>
+         <property name="top_attach">4</property>
+         <property name="bottom_attach">5</property>
+         <property name="y_options"></property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkButton" id="button_forget">
+         <property name="visible">True</property>
+         <property name="tooltip" translatable="yes">Forget password and clear the entry.</property>
+         <property name="can_focus">True</property>
+         <property name="relief">GTK_RELIEF_NORMAL</property>
+         <property name="focus_on_click">True</property>
+
+         <child>
+           <widget class="GtkImage" id="image834">
+             <property name="visible">True</property>
+             <property name="stock">gtk-clear</property>
+             <property name="icon_size">1</property>
+             <property name="xalign">0.5</property>
+             <property name="yalign">0.5</property>
+             <property name="xpad">0</property>
+             <property name="ypad">0</property>
+           </widget>
+         </child>
+       </widget>
+       <packing>
+         <property name="left_attach">2</property>
+         <property name="right_attach">3</property>
+         <property name="top_attach">1</property>
+         <property name="bottom_attach">2</property>
+         <property name="x_options">fill</property>
+         <property name="y_options"></property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkEntry" id="entry_password">
+         <property name="visible">True</property>
+         <property name="can_focus">True</property>
+         <property name="editable">True</property>
+         <property name="visibility">False</property>
+         <property name="max_length">0</property>
+         <property name="text" translatable="yes"></property>
+         <property name="has_frame">True</property>
+         <property name="invisible_char">*</property>
+         <property name="activates_default">False</property>
+       </widget>
+       <packing>
+         <property name="left_attach">1</property>
+         <property name="right_attach">2</property>
+         <property name="top_attach">1</property>
+         <property name="bottom_attach">2</property>
+         <property name="y_options"></property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkEntry" id="entry_id">
+         <property name="visible">True</property>
+         <property name="can_focus">True</property>
+         <property name="editable">True</property>
+         <property name="visibility">True</property>
+         <property name="max_length">0</property>
+         <property name="text" translatable="yes"></property>
+         <property name="has_frame">True</property>
+         <property name="invisible_char">*</property>
+         <property name="activates_default">False</property>
+       </widget>
+       <packing>
+         <property name="left_attach">1</property>
+         <property name="right_attach">3</property>
+         <property name="top_attach">0</property>
+         <property name="bottom_attach">1</property>
+         <property name="y_options"></property>
+       </packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
+</glade-interface>
diff --git a/libempathy-gtk/empathy-account-widget-jabber.h b/libempathy-gtk/empathy-account-widget-jabber.h
new file mode 100644 (file)
index 0000000..99205c9
--- /dev/null
@@ -0,0 +1,34 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * 
+ * Authors: Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_ACCOUNT_WIDGET_JABBER_H__
+#define __EMPATHY_ACCOUNT_WIDGET_JABBER_H__
+
+#include <libmissioncontrol/mc-account.h>
+
+G_BEGIN_DECLS
+
+GtkWidget *empathy_account_widget_jabber_new (McAccount *account);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_ACCOUNT_WIDGET_JABBER_H__ */
diff --git a/libempathy-gtk/empathy-accounts-dialog.c b/libempathy-gtk/empathy-accounts-dialog.c
new file mode 100644 (file)
index 0000000..0e5f909
--- /dev/null
@@ -0,0 +1,1037 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2005-2007 Imendio AB
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * 
+ * Authors: Martyn Russell <martyn@imendio.com>
+ *          Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+#include <glib/gi18n.h>
+#include <dbus/dbus-glib.h>
+
+#include <libmissioncontrol/mc-account.h>
+#include <libmissioncontrol/mc-profile.h>
+#include <libmissioncontrol/mission-control.h>
+#include <libmissioncontrol/mc-account-monitor.h>
+#include <libtelepathy/tp-constants.h>
+
+#include <libempathy/empathy-debug.h>
+#include <libempathy/empathy-utils.h>
+#include <libempathy-gtk/empathy-ui-utils.h>
+
+#include "empathy-accounts-dialog.h"
+#include "empathy-profile-chooser.h"
+#include "empathy-account-widget-generic.h"
+#include "empathy-account-widget-jabber.h"
+
+#define DEBUG_DOMAIN "AccountDialog"
+
+/* Flashing delay for icons (milliseconds). */
+#define FLASH_TIMEOUT 500
+
+typedef struct {
+       GtkWidget        *window;
+
+       GtkWidget        *alignment_settings;
+
+       GtkWidget        *vbox_details;
+       GtkWidget        *frame_no_account;
+       GtkWidget        *label_no_account;
+       GtkWidget        *label_no_account_blurb;
+
+       GtkWidget        *treeview;
+
+       GtkWidget        *button_remove;
+       GtkWidget        *button_connect;
+
+       GtkWidget        *frame_new_account;
+       GtkWidget        *combobox_profile;
+       GtkWidget        *entry_name;
+       GtkWidget        *table_new_account;
+       GtkWidget        *button_create;
+       GtkWidget        *button_back;
+
+       GtkWidget        *image_type;
+       GtkWidget        *label_name;
+       GtkWidget        *label_type;
+       GtkWidget        *settings_widget;
+
+       gboolean          connecting_show;
+       guint             connecting_id;
+       gboolean          account_changed;
+
+       MissionControl   *mc;
+       McAccountMonitor *monitor;
+} EmpathyAccountsDialog;
+
+enum {
+       COL_NAME,
+       COL_STATUS,
+       COL_ACCOUNT_POINTER,
+       COL_COUNT
+};
+
+static void       accounts_dialog_setup                     (EmpathyAccountsDialog            *dialog);
+static void       accounts_dialog_update_account            (EmpathyAccountsDialog            *dialog,
+                                                            McAccount                       *account);
+static void       accounts_dialog_model_setup               (EmpathyAccountsDialog            *dialog);
+static void       accounts_dialog_model_add_columns         (EmpathyAccountsDialog            *dialog);
+static void       accounts_dialog_model_select_first        (EmpathyAccountsDialog            *dialog);
+static void       accounts_dialog_model_pixbuf_data_func    (GtkTreeViewColumn               *tree_column,
+                                                            GtkCellRenderer                 *cell,
+                                                            GtkTreeModel                    *model,
+                                                            GtkTreeIter                     *iter,
+                                                            EmpathyAccountsDialog            *dialog);
+static McAccount *accounts_dialog_model_get_selected        (EmpathyAccountsDialog            *dialog);
+static void       accounts_dialog_model_set_selected        (EmpathyAccountsDialog            *dialog,
+                                                            McAccount                       *account);
+static gboolean   accounts_dialog_model_remove_selected     (EmpathyAccountsDialog            *dialog);
+static void       accounts_dialog_model_selection_changed   (GtkTreeSelection                *selection,
+                                                            EmpathyAccountsDialog            *dialog);
+static void       accounts_dialog_add_account               (EmpathyAccountsDialog            *dialog,
+                                                            McAccount                       *account);
+static void       accounts_dialog_account_added_cb          (McAccountMonitor                *monitor,
+                                                            gchar                           *unique_name,
+                                                            EmpathyAccountsDialog            *dialog);
+static void       accounts_dialog_account_removed_cb        (McAccountMonitor                *monitor,
+                                                            gchar                           *unique_name,
+                                                            EmpathyAccountsDialog            *dialog);
+static gboolean   accounts_dialog_row_changed_foreach       (GtkTreeModel                    *model,
+                                                            GtkTreePath                     *path,
+                                                            GtkTreeIter                     *iter,
+                                                            gpointer                         user_data);
+static gboolean   accounts_dialog_flash_connecting_cb       (EmpathyAccountsDialog            *dialog);
+static void       accounts_dialog_status_changed_cb         (MissionControl                  *mc,
+                                                            TelepathyConnectionStatus        status,
+                                                            McPresence                       presence,
+                                                            TelepathyConnectionStatusReason  reason,
+                                                            const gchar                     *unique_name,
+                                                            EmpathyAccountsDialog            *dialog);
+static void       accounts_dialog_entry_name_changed_cb     (GtkWidget                       *widget,
+                                                            EmpathyAccountsDialog            *dialog);
+static void       accounts_dialog_button_create_clicked_cb  (GtkWidget                       *button,
+                                                            EmpathyAccountsDialog            *dialog);
+static void       accounts_dialog_button_back_clicked_cb    (GtkWidget                       *button,
+                                                            EmpathyAccountsDialog            *dialog);
+static void       accounts_dialog_button_connect_clicked_cb (GtkWidget                       *button,
+                                                            EmpathyAccountsDialog            *dialog);
+static void       accounts_dialog_button_add_clicked_cb     (GtkWidget                       *button,
+                                                            EmpathyAccountsDialog            *dialog);
+static void       accounts_dialog_remove_response_cb        (GtkWidget                       *dialog,
+                                                            gint                             response,
+                                                            McAccount                       *account);
+static void       accounts_dialog_button_remove_clicked_cb  (GtkWidget                       *button,
+                                                            EmpathyAccountsDialog            *dialog);
+static void       accounts_dialog_treeview_row_activated_cb (GtkTreeView                     *tree_view,
+                                                            GtkTreePath                     *path,
+                                                            GtkTreeViewColumn               *column,
+                                                            EmpathyAccountsDialog            *dialog);
+static void       accounts_dialog_response_cb               (GtkWidget                       *widget,
+                                                            gint                             response,
+                                                            EmpathyAccountsDialog            *dialog);
+static void       accounts_dialog_destroy_cb                (GtkWidget                       *widget,
+                                                            EmpathyAccountsDialog            *dialog);
+
+static void
+accounts_dialog_setup (EmpathyAccountsDialog *dialog)
+{
+       GtkTreeView      *view;
+       GtkListStore     *store;
+       GtkTreeSelection *selection;
+       GtkTreeIter       iter;
+       GList            *accounts, *l;
+
+       view = GTK_TREE_VIEW (dialog->treeview);
+       store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
+       selection = gtk_tree_view_get_selection (view);
+
+       accounts = mc_accounts_list ();
+
+       for (l = accounts; l; l = l->next) {
+               McAccount                 *account;
+               const gchar               *name;
+               TelepathyConnectionStatus  status;
+
+               account = l->data;
+
+               name = mc_account_get_display_name (account);
+               if (!name) {
+                       continue;
+               }
+
+               status = mission_control_get_connection_status (dialog->mc, account, NULL);
+
+               gtk_list_store_insert_with_values (store, &iter,
+                                                  -1,
+                                                  COL_NAME, name,
+                                                  COL_STATUS, status,
+                                                  COL_ACCOUNT_POINTER, account,
+                                                  -1);
+
+               accounts_dialog_status_changed_cb (dialog->mc,
+                                                  status,
+                                                  MC_PRESENCE_UNSET,
+                                                  TP_CONN_STATUS_REASON_NONE_SPECIFIED,
+                                                  mc_account_get_unique_name (account),
+                                                  dialog);
+
+               g_object_unref (account);
+       }
+
+       g_list_free (accounts);
+}
+
+static void
+accounts_dialog_update_connect_button (EmpathyAccountsDialog *dialog)
+{
+       McAccount   *account;
+       GtkWidget   *image;
+       const gchar *stock_id;
+       const gchar *label;
+
+       account = accounts_dialog_model_get_selected (dialog);
+       
+       if (!account) {
+               gtk_widget_set_sensitive (dialog->button_connect, FALSE);
+               return;
+       }
+
+       if (mc_account_is_enabled (account)) {
+               label = _("Disable");
+               stock_id = GTK_STOCK_DISCONNECT;
+       } else {
+               label = _("Enable");
+               stock_id = GTK_STOCK_CONNECT;
+       }
+
+       image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON);
+
+       gtk_button_set_label (GTK_BUTTON (dialog->button_connect), label);
+       gtk_button_set_image (GTK_BUTTON (dialog->button_connect), image);
+}
+
+static void
+accounts_dialog_update_account (EmpathyAccountsDialog *dialog,
+                               McAccount            *account)
+{
+       if (dialog->settings_widget) {
+               gtk_widget_destroy (dialog->settings_widget);
+               dialog->settings_widget = NULL;
+       }
+
+       if (!account) {
+               GtkTreeView  *view;
+               GtkTreeModel *model;
+
+               gtk_widget_show (dialog->frame_no_account);
+               gtk_widget_hide (dialog->vbox_details);
+
+               gtk_widget_set_sensitive (dialog->button_connect, FALSE);
+               gtk_widget_set_sensitive (dialog->button_remove, FALSE);
+
+               view = GTK_TREE_VIEW (dialog->treeview);
+               model = gtk_tree_view_get_model (view);
+
+               if (gtk_tree_model_iter_n_children (model, NULL) > 0) {
+                       gtk_label_set_markup (GTK_LABEL (dialog->label_no_account),
+                                             _("<b>No Account Selected</b>"));
+                       gtk_label_set_markup (GTK_LABEL (dialog->label_no_account_blurb),
+                                             _("To add a new account, you can click on the "
+                                               "'Add' button and a new entry will be created "
+                                               "for you to start configuring.\n"
+                                               "\n"
+                                               "If you do not want to add an account, simply "
+                                               "click on the account you want to configure in "
+                                               "the list on the left."));
+               } else {
+                       gtk_label_set_markup (GTK_LABEL (dialog->label_no_account),
+                                             _("<b>No Accounts Configured</b>"));
+                       gtk_label_set_markup (GTK_LABEL (dialog->label_no_account_blurb),
+                                             _("To add a new account, you can click on the "
+                                               "'Add' button and a new entry will be created "
+                                               "for you to start configuring."));
+               }
+       } else {
+               McProfile *profile;
+               const gchar *config_ui;
+
+               gtk_widget_hide (dialog->frame_no_account);
+               gtk_widget_show (dialog->vbox_details);
+
+               profile = mc_account_get_profile (account);
+               config_ui = mc_profile_get_configuration_ui (profile);
+
+               if (strcmp (config_ui, "jabber") == 0) {
+                       dialog->settings_widget = 
+                               empathy_account_widget_jabber_new (account);
+               } else {
+                       dialog->settings_widget = 
+                               empathy_account_widget_generic_new (account,
+                                                                  dialog->label_name);
+               }
+               
+               gtk_widget_grab_focus (dialog->settings_widget);
+       }
+
+       if (dialog->settings_widget) {
+               gtk_container_add (GTK_CONTAINER (dialog->alignment_settings),
+                                  dialog->settings_widget);
+       }
+
+       if (account) {
+               McProfile *profile;
+
+               profile = mc_account_get_profile (account);
+               gtk_image_set_from_icon_name (GTK_IMAGE (dialog->image_type),
+                                             mc_profile_get_icon_name (profile),
+                                             GTK_ICON_SIZE_DIALOG);
+               
+
+               gtk_label_set_text (GTK_LABEL (dialog->label_type),
+                                   mc_profile_get_display_name (profile));
+               gtk_label_set_text (GTK_LABEL (dialog->label_name), 
+                                   mc_account_get_display_name (account));
+       }
+}
+
+static void
+accounts_dialog_model_setup (EmpathyAccountsDialog *dialog)
+{
+       GtkListStore     *store;
+       GtkTreeSelection *selection;
+
+       store = gtk_list_store_new (COL_COUNT,
+                                   G_TYPE_STRING,     /* name */
+                                   G_TYPE_UINT,       /* status */
+                                   MC_TYPE_ACCOUNT);  /* account */
+
+       gtk_tree_view_set_model (GTK_TREE_VIEW (dialog->treeview),
+                                GTK_TREE_MODEL (store));
+
+       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->treeview));
+       gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+
+       g_signal_connect (selection, "changed",
+                         G_CALLBACK (accounts_dialog_model_selection_changed),
+                         dialog);
+
+       gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
+                                             COL_NAME, GTK_SORT_ASCENDING);
+
+       accounts_dialog_model_add_columns (dialog);
+
+       g_object_unref (store);
+}
+
+static void
+accounts_dialog_model_add_columns (EmpathyAccountsDialog *dialog)
+{
+       GtkTreeView       *view;
+       GtkTreeViewColumn *column;
+       GtkCellRenderer   *cell;
+
+       view = GTK_TREE_VIEW (dialog->treeview);
+       gtk_tree_view_set_headers_visible (view, TRUE);
+
+       /* account name/status */
+       column = gtk_tree_view_column_new ();
+       gtk_tree_view_column_set_title (column, _("Accounts"));
+
+       cell = gtk_cell_renderer_pixbuf_new ();
+       gtk_tree_view_column_pack_start (column, cell, FALSE);
+       gtk_tree_view_column_set_cell_data_func (column, cell,
+                                                (GtkTreeCellDataFunc)
+                                                accounts_dialog_model_pixbuf_data_func,
+                                                dialog,
+                                                NULL);
+
+       cell = gtk_cell_renderer_text_new ();
+       g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+       gtk_tree_view_column_pack_start (column, cell, TRUE);
+       gtk_tree_view_column_add_attribute (column,
+                                           cell,
+                                           "text", COL_NAME);
+
+       gtk_tree_view_column_set_expand (column, TRUE);
+       gtk_tree_view_append_column (view, column);
+}
+
+static void
+accounts_dialog_model_select_first (EmpathyAccountsDialog *dialog)
+{
+       GtkTreeView      *view;
+       GtkTreeModel     *model;
+       GtkTreeSelection *selection;
+       GtkTreeIter       iter;
+
+       /* select first */
+       view = GTK_TREE_VIEW (dialog->treeview);
+       model = gtk_tree_view_get_model (view);
+       
+       if (gtk_tree_model_get_iter_first (model, &iter)) {
+               selection = gtk_tree_view_get_selection (view);
+               gtk_tree_selection_select_iter (selection, &iter);
+       } else {
+               accounts_dialog_update_account (dialog, NULL);
+       }
+}
+
+static void
+accounts_dialog_model_pixbuf_data_func (GtkTreeViewColumn    *tree_column,
+                                       GtkCellRenderer      *cell,
+                                       GtkTreeModel         *model,
+                                       GtkTreeIter          *iter,
+                                       EmpathyAccountsDialog *dialog)
+{
+       McAccount                 *account;
+       const gchar               *icon_name;
+       GdkPixbuf                 *pixbuf;
+       TelepathyConnectionStatus  status;
+
+       gtk_tree_model_get (model, iter,
+                           COL_STATUS, &status,
+                           COL_ACCOUNT_POINTER, &account,
+                           -1);
+
+       icon_name = empathy_icon_name_from_account (account);
+       pixbuf = empathy_pixbuf_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON);
+
+       if (pixbuf) {
+               if (status == TP_CONN_STATUS_DISCONNECTED ||
+                   (status == TP_CONN_STATUS_CONNECTING && 
+                    !dialog->connecting_show)) {
+                       GdkPixbuf *modded_pixbuf;
+
+                       modded_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+                                                       TRUE,
+                                                       8,
+                                                       gdk_pixbuf_get_width (pixbuf),
+                                                       gdk_pixbuf_get_height (pixbuf));
+
+                       gdk_pixbuf_saturate_and_pixelate (pixbuf,
+                                                         modded_pixbuf,
+                                                         1.0,
+                                                         TRUE);
+                       g_object_unref (pixbuf);
+                       pixbuf = modded_pixbuf;
+               }
+       }
+
+       g_object_set (cell,
+                     "visible", TRUE,
+                     "pixbuf", pixbuf,
+                     NULL);
+
+       g_object_unref (account);
+       if (pixbuf) {
+               g_object_unref (pixbuf);
+       }
+}
+
+static McAccount *
+accounts_dialog_model_get_selected (EmpathyAccountsDialog *dialog)
+{
+       GtkTreeView      *view;
+       GtkTreeModel     *model;
+       GtkTreeSelection *selection;
+       GtkTreeIter       iter;
+       McAccount        *account;
+
+       view = GTK_TREE_VIEW (dialog->treeview);
+       selection = gtk_tree_view_get_selection (view);
+
+       if (!gtk_tree_selection_get_selected (selection, &model, &iter)) {
+               return NULL;
+       }
+
+       gtk_tree_model_get (model, &iter, COL_ACCOUNT_POINTER, &account, -1);
+
+       return account;
+}
+
+static void
+accounts_dialog_model_set_selected (EmpathyAccountsDialog *dialog,
+                                   McAccount            *account)
+{
+       GtkTreeView      *view;
+       GtkTreeSelection *selection;
+       GtkTreeModel     *model;
+       GtkTreeIter       iter;
+       gboolean          ok;
+
+       view = GTK_TREE_VIEW (dialog->treeview);
+       model = gtk_tree_view_get_model (view);
+       selection = gtk_tree_view_get_selection (view);
+
+       for (ok = gtk_tree_model_get_iter_first (model, &iter);
+            ok;
+            ok = gtk_tree_model_iter_next (model, &iter)) {
+               McAccount *this_account;
+               gboolean   equal;
+
+               gtk_tree_model_get (model, &iter,
+                                   COL_ACCOUNT_POINTER, &this_account,
+                                   -1);
+
+               equal = empathy_account_equal (this_account, account);
+               g_object_unref (this_account);
+
+               if (equal) {
+                       gtk_tree_selection_select_iter (selection, &iter);
+                       break;
+               }
+       }
+}
+
+static gboolean
+accounts_dialog_model_remove_selected (EmpathyAccountsDialog *dialog)
+{
+       GtkTreeView      *view;
+       GtkTreeModel     *model;
+       GtkTreeSelection *selection;
+       GtkTreeIter       iter;
+
+       view = GTK_TREE_VIEW (dialog->treeview);
+       selection = gtk_tree_view_get_selection (view);
+
+       if (!gtk_tree_selection_get_selected (selection, &model, &iter)) {
+               return FALSE;
+       }
+
+       return gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+}
+
+static void
+accounts_dialog_model_selection_changed (GtkTreeSelection     *selection,
+                                        EmpathyAccountsDialog *dialog)
+{
+       McAccount    *account;
+       GtkTreeModel *model;
+       GtkTreeIter   iter;
+       gboolean      is_selection;
+
+       is_selection = gtk_tree_selection_get_selected (selection, &model, &iter);
+
+       gtk_widget_set_sensitive (dialog->button_remove, is_selection);
+       gtk_widget_set_sensitive (dialog->button_connect, is_selection);
+
+       accounts_dialog_update_connect_button (dialog);
+
+       account = accounts_dialog_model_get_selected (dialog);
+       accounts_dialog_update_account (dialog, account);
+
+       if (account) {
+               g_object_unref (account);
+       }
+}
+
+static void
+accounts_dialog_add_account (EmpathyAccountsDialog *dialog,
+                            McAccount            *account)
+{
+       TelepathyConnectionStatus  status;
+       const gchar               *name;
+       GtkTreeView               *view;
+       GtkTreeModel              *model;
+       GtkListStore              *store;
+       GtkTreeIter                iter;
+       gboolean                   ok;
+
+       view = GTK_TREE_VIEW (dialog->treeview);
+       model = gtk_tree_view_get_model (view);
+       store = GTK_LIST_STORE (model);
+
+       for (ok = gtk_tree_model_get_iter_first (model, &iter);
+            ok;
+            ok = gtk_tree_model_iter_next (model, &iter)) {
+               McAccount *this_account;
+               gboolean   equal;
+
+               gtk_tree_model_get (model, &iter,
+                                   COL_ACCOUNT_POINTER, &this_account,
+                                   -1);
+
+               equal =  empathy_account_equal (this_account, account);
+               g_object_unref (this_account);
+
+               if (equal) {
+                       return;
+               }
+       }
+
+       status = mission_control_get_connection_status (dialog->mc, account, NULL);
+       name = mc_account_get_display_name (account);
+
+       g_return_if_fail (name != NULL);
+
+       empathy_debug (DEBUG_DOMAIN, "Adding new account: %s", name);
+
+       gtk_list_store_insert_with_values (store, &iter,
+                                          -1,
+                                          COL_NAME, name,
+                                          COL_STATUS, status,
+                                          COL_ACCOUNT_POINTER, account,
+                                          -1);
+}
+
+static void
+accounts_dialog_account_added_cb (McAccountMonitor     *monitor,
+                                 gchar                *unique_name,
+                                 EmpathyAccountsDialog *dialog)
+{
+       McAccount *account;
+
+       account = mc_account_lookup (unique_name);
+       accounts_dialog_add_account (dialog, account);
+       g_object_unref (account);
+}
+
+static void
+accounts_dialog_account_removed_cb (McAccountMonitor     *monitor,
+                                   gchar                *unique_name,
+                                   EmpathyAccountsDialog *dialog)
+{
+       McAccount *account;
+
+       account = mc_account_lookup (unique_name);
+
+       accounts_dialog_model_set_selected (dialog, account);
+       accounts_dialog_model_remove_selected (dialog);
+
+       g_object_unref (account);
+}
+
+static gboolean
+accounts_dialog_row_changed_foreach (GtkTreeModel *model,
+                                    GtkTreePath  *path,
+                                    GtkTreeIter  *iter,
+                                    gpointer      user_data)
+{
+       gtk_tree_model_row_changed (model, path, iter);
+
+       return FALSE;
+}
+
+static gboolean
+accounts_dialog_flash_connecting_cb (EmpathyAccountsDialog *dialog)
+{
+       GtkTreeView  *view;
+       GtkTreeModel *model;
+
+       dialog->connecting_show = !dialog->connecting_show;
+
+       view = GTK_TREE_VIEW (dialog->treeview);
+       model = gtk_tree_view_get_model (view);
+
+       gtk_tree_model_foreach (model, accounts_dialog_row_changed_foreach, NULL);
+
+       return TRUE;
+}
+
+static void
+accounts_dialog_status_changed_cb (MissionControl                  *mc,
+                                  TelepathyConnectionStatus        status,
+                                  McPresence                       presence,
+                                  TelepathyConnectionStatusReason  reason,
+                                  const gchar                     *unique_name,
+                                  EmpathyAccountsDialog            *dialog)
+{
+       GtkTreeView      *view;
+       GtkTreeSelection *selection;
+       GtkTreeModel     *model;
+       GtkTreeIter       iter;
+       gboolean          ok;
+       McAccount        *account;
+       GList            *accounts, *l;
+       gboolean          found = FALSE;
+       
+       /* Update the status in the model */
+       view = GTK_TREE_VIEW (dialog->treeview);
+       selection = gtk_tree_view_get_selection (view);
+       model = gtk_tree_view_get_model (view);
+       account = mc_account_lookup (unique_name);
+
+       empathy_debug (DEBUG_DOMAIN, "Status changed for account %s: "
+                     "status=%d presence=%d",
+                     unique_name, status, presence);
+
+       for (ok = gtk_tree_model_get_iter_first (model, &iter);
+            ok;
+            ok = gtk_tree_model_iter_next (model, &iter)) {
+               McAccount *this_account;
+               gboolean   equal;
+
+               gtk_tree_model_get (model, &iter,
+                                   COL_ACCOUNT_POINTER, &this_account,
+                                   -1);
+
+               equal = empathy_account_equal (this_account, account);
+               g_object_unref (this_account);
+
+               if (equal) {
+                       GtkTreePath *path;
+
+                       gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+                                           COL_STATUS, status,
+                                           -1);
+
+                       path = gtk_tree_model_get_path (model, &iter);
+                       gtk_tree_model_row_changed (model, path, &iter);
+                       gtk_tree_path_free (path);
+
+                       break;
+               }
+       }
+
+       g_object_unref (account);
+
+       /* Start to flash account if status is connecting */
+       if (status == TP_CONN_STATUS_CONNECTING) {
+               if (!dialog->connecting_id) {
+                       dialog->connecting_id = g_timeout_add (FLASH_TIMEOUT,
+                                                              (GSourceFunc) accounts_dialog_flash_connecting_cb,
+                                                              dialog);
+               }
+
+               return;
+       }
+
+       /* Stop to flash if no account is connecting */
+       accounts = mc_accounts_list ();
+       for (l = accounts; l; l = l->next) {
+               McAccount *this_account;
+
+               this_account = l->data;
+
+               if (mission_control_get_connection_status (mc, this_account, NULL) == TP_CONN_STATUS_CONNECTING) {
+                       found = TRUE;
+                       break;
+               }
+
+               g_object_unref (this_account);
+       }
+       g_list_free (accounts);
+
+       if (!found && dialog->connecting_id) {
+               g_source_remove (dialog->connecting_id);
+               dialog->connecting_id = 0;
+       }
+
+       gtk_widget_show (dialog->window);
+}
+
+static void          
+accounts_dialog_entry_name_changed_cb (GtkWidget             *widget,
+                                      EmpathyAccountsDialog  *dialog)
+{
+       const gchar *str;
+       
+       str = gtk_entry_get_text (GTK_ENTRY (widget));
+       gtk_widget_set_sensitive (dialog->button_create, !G_STR_EMPTY (str));
+}
+
+static void
+accounts_dialog_button_create_clicked_cb (GtkWidget             *button,
+                                         EmpathyAccountsDialog  *dialog)
+{
+       McProfile   *profile;
+       McAccount   *account;
+       const gchar *str;
+
+       /* Update widgets */
+       gtk_widget_show (dialog->vbox_details);
+       gtk_widget_hide (dialog->frame_no_account);
+       gtk_widget_hide (dialog->frame_new_account);
+
+       profile = empathy_profile_chooser_get_selected (dialog->combobox_profile);
+
+       /* Create account */
+       account = mc_account_create (profile);
+
+       str = gtk_entry_get_text (GTK_ENTRY (dialog->entry_name));
+       mc_account_set_display_name (account, str);
+
+       accounts_dialog_add_account (dialog, account);
+       accounts_dialog_model_set_selected (dialog, account);
+
+       g_object_unref (account);
+       g_object_unref (profile);
+}
+
+static void
+accounts_dialog_button_back_clicked_cb (GtkWidget             *button,
+                                       EmpathyAccountsDialog  *dialog)
+{
+       McAccount *account;
+
+       gtk_widget_hide (dialog->vbox_details);
+       gtk_widget_hide (dialog->frame_no_account);
+       gtk_widget_hide (dialog->frame_new_account);
+
+       account = accounts_dialog_model_get_selected (dialog);
+       accounts_dialog_update_account (dialog, account);
+}
+
+static void
+accounts_dialog_button_connect_clicked_cb (GtkWidget            *button,
+                                          EmpathyAccountsDialog *dialog)
+{
+       McAccount *account;
+       gboolean   enable;
+
+       account = accounts_dialog_model_get_selected (dialog);
+       enable = (!mc_account_is_enabled (account));
+       mc_account_set_enabled (account, enable);
+       accounts_dialog_update_connect_button (dialog);
+
+       g_object_unref (account);
+}
+
+static void
+accounts_dialog_button_add_clicked_cb (GtkWidget            *button,
+                                      EmpathyAccountsDialog *dialog)
+{
+       gtk_widget_hide (dialog->vbox_details);
+       gtk_widget_hide (dialog->frame_no_account);
+       gtk_widget_show (dialog->frame_new_account);
+
+       gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->combobox_profile), 0);
+       gtk_entry_set_text (GTK_ENTRY (dialog->entry_name), "");
+       gtk_widget_grab_focus (dialog->entry_name);
+}
+
+static void
+accounts_dialog_remove_response_cb (GtkWidget *dialog,
+                                   gint       response,
+                                   McAccount *account)
+{
+       if (response == GTK_RESPONSE_YES) {
+               mc_account_delete (account);
+       }
+
+       gtk_widget_destroy (dialog);
+}
+
+static void
+accounts_dialog_button_remove_clicked_cb (GtkWidget            *button,
+                                         EmpathyAccountsDialog *dialog)
+{
+       McAccount *account;
+       GtkWidget *message_dialog;
+
+       account = accounts_dialog_model_get_selected (dialog);
+
+       if (!mc_account_is_complete (account)) {
+               accounts_dialog_model_remove_selected (dialog);
+               return;
+       }
+       message_dialog = gtk_message_dialog_new
+               (GTK_WINDOW (dialog->window),
+                GTK_DIALOG_DESTROY_WITH_PARENT,
+                GTK_MESSAGE_QUESTION,
+                GTK_BUTTONS_NONE,
+                _("You are about to remove your %s account!\n"
+                  "Are you sure you want to proceed?"),
+                mc_account_get_display_name (account));
+
+       gtk_message_dialog_format_secondary_text
+               (GTK_MESSAGE_DIALOG (message_dialog),
+                _("Any associated conversations and chat rooms will NOT be "
+                  "removed if you decide to proceed.\n"
+                  "\n"
+                  "Should you decide to add the account back at a later time, "
+                  "they will still be available."));
+
+       gtk_dialog_add_button (GTK_DIALOG (message_dialog),
+                              GTK_STOCK_CANCEL, 
+                              GTK_RESPONSE_NO);
+       gtk_dialog_add_button (GTK_DIALOG (message_dialog),
+                              GTK_STOCK_REMOVE, 
+                              GTK_RESPONSE_YES);
+
+       g_signal_connect (message_dialog, "response",
+                         G_CALLBACK (accounts_dialog_remove_response_cb),
+                         account);
+
+       gtk_widget_show (message_dialog);
+}
+
+static void
+accounts_dialog_treeview_row_activated_cb (GtkTreeView          *tree_view,
+                                          GtkTreePath          *path,
+                                          GtkTreeViewColumn    *column,
+                                          EmpathyAccountsDialog *dialog)
+{
+
+       accounts_dialog_button_connect_clicked_cb (dialog->button_connect,
+                                                  dialog);
+}
+
+static void
+accounts_dialog_response_cb (GtkWidget            *widget,
+                            gint                  response,
+                            EmpathyAccountsDialog *dialog)
+{
+       gtk_widget_destroy (widget);
+}
+
+static void
+accounts_dialog_destroy_cb (GtkWidget            *widget,
+                           EmpathyAccountsDialog *dialog)
+{
+       GList *accounts, *l;
+
+       /* Disconnect signals */
+       g_signal_handlers_disconnect_by_func (dialog->monitor,
+                                             accounts_dialog_account_added_cb,
+                                             dialog);
+       g_signal_handlers_disconnect_by_func (dialog->monitor,
+                                             accounts_dialog_account_removed_cb,
+                                             dialog);
+       dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (dialog->mc),
+                                       "AccountStatusChanged",
+                                       G_CALLBACK (accounts_dialog_status_changed_cb),
+                                       dialog);
+
+       /* Delete incomplete accounts */
+       accounts = mc_accounts_list ();
+       for (l = accounts; l; l = l->next) {
+               McAccount *account;
+
+               account = l->data;
+               if (!mc_account_is_complete (account)) {
+                       /* FIXME: Warn the user the account is not complete
+                        *        and is going to be removed. */
+                       mc_account_delete (account);
+               }
+
+               g_object_unref (account);
+       }
+       g_list_free (accounts);
+
+       if (dialog->connecting_id) {
+               g_source_remove (dialog->connecting_id);
+       }
+
+       g_object_unref (dialog->mc);
+       g_object_unref (dialog->monitor);
+       
+       g_free (dialog);
+}
+
+GtkWidget *
+empathy_accounts_dialog_show (GtkWindow *parent)
+{
+       static EmpathyAccountsDialog *dialog = NULL;
+       GladeXML                    *glade;
+       GtkWidget                   *bbox;
+       GtkWidget                   *button_close;
+
+       if (dialog) {
+               gtk_window_present (GTK_WINDOW (dialog->window));
+               return dialog->window;
+       }
+
+       dialog = g_new0 (EmpathyAccountsDialog, 1);
+
+       glade = empathy_glade_get_file ("empathy-accounts-dialog.glade",
+                                      "accounts_dialog",
+                                      NULL,
+                                      "accounts_dialog", &dialog->window,
+                                      "vbox_details", &dialog->vbox_details,
+                                      "frame_no_account", &dialog->frame_no_account,
+                                      "label_no_account", &dialog->label_no_account,
+                                      "label_no_account_blurb", &dialog->label_no_account_blurb,
+                                      "alignment_settings", &dialog->alignment_settings,
+                                      "dialog-action_area", &bbox,
+                                      "treeview", &dialog->treeview,
+                                      "frame_new_account", &dialog->frame_new_account,
+                                      "entry_name", &dialog->entry_name,
+                                      "table_new_account", &dialog->table_new_account,
+                                      "button_create", &dialog->button_create,
+                                      "button_back", &dialog->button_back,
+                                      "image_type", &dialog->image_type,
+                                      "label_type", &dialog->label_type,
+                                      "label_name", &dialog->label_name,
+                                      "button_remove", &dialog->button_remove,
+                                      "button_connect", &dialog->button_connect,
+                                      "button_close", &button_close,
+                                      NULL);
+
+       empathy_glade_connect (glade,
+                             dialog,
+                             "accounts_dialog", "destroy", accounts_dialog_destroy_cb,
+                             "accounts_dialog", "response", accounts_dialog_response_cb,
+                             "button_create", "clicked", accounts_dialog_button_create_clicked_cb,
+                             "button_back", "clicked", accounts_dialog_button_back_clicked_cb,
+                             "entry_name", "changed", accounts_dialog_entry_name_changed_cb,
+                             "treeview", "row-activated", accounts_dialog_treeview_row_activated_cb,
+                             "button_connect", "clicked", accounts_dialog_button_connect_clicked_cb,
+                             "button_add", "clicked", accounts_dialog_button_add_clicked_cb,
+                             "button_remove", "clicked", accounts_dialog_button_remove_clicked_cb,
+                             NULL);
+
+       g_object_add_weak_pointer (G_OBJECT (dialog->window), (gpointer) &dialog);
+
+       g_object_unref (glade);
+
+       /* Create profile chooser */
+       dialog->combobox_profile = empathy_profile_chooser_new ();
+       gtk_table_attach_defaults (GTK_TABLE (dialog->table_new_account),
+                                  dialog->combobox_profile,
+                                  1, 2,
+                                  0, 1);
+       gtk_widget_show (dialog->combobox_profile);
+
+       /* Set up signalling */
+       dialog->mc = empathy_mission_control_new ();
+       dialog->monitor = mc_account_monitor_new ();
+
+       /* FIXME: connect account-enabled/disabled too */
+       g_signal_connect (dialog->monitor, "account-created",
+                         G_CALLBACK (accounts_dialog_account_added_cb),
+                         dialog);
+       g_signal_connect (dialog->monitor, "account-deleted",
+                         G_CALLBACK (accounts_dialog_account_removed_cb),
+                         dialog);
+       dbus_g_proxy_connect_signal (DBUS_G_PROXY (dialog->mc), "AccountStatusChanged",
+                                    G_CALLBACK (accounts_dialog_status_changed_cb),
+                                    dialog, NULL);
+
+       accounts_dialog_model_setup (dialog);
+       accounts_dialog_setup (dialog);
+       accounts_dialog_model_select_first (dialog);
+
+       if (parent) {
+               gtk_window_set_transient_for (GTK_WINDOW (dialog->window),
+                                             GTK_WINDOW (parent));
+       }
+
+       gtk_widget_show (dialog->window);
+
+       return dialog->window;
+}
+
diff --git a/libempathy-gtk/empathy-accounts-dialog.glade b/libempathy-gtk/empathy-accounts-dialog.glade
new file mode 100644 (file)
index 0000000..05ba64f
--- /dev/null
@@ -0,0 +1,757 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkDialog" id="accounts_dialog">
+  <property name="border_width">5</property>
+  <property name="title" translatable="yes">Accounts</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_NONE</property>
+  <property name="modal">False</property>
+  <property name="resizable">True</property>
+  <property name="destroy_with_parent">False</property>
+  <property name="decorated">True</property>
+  <property name="skip_taskbar_hint">False</property>
+  <property name="skip_pager_hint">False</property>
+  <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+  <property name="focus_on_map">True</property>
+  <property name="urgency_hint">False</property>
+  <property name="has_separator">False</property>
+
+  <child internal-child="vbox">
+    <widget class="GtkVBox" id="dialog-vbox3">
+      <property name="visible">True</property>
+      <property name="homogeneous">False</property>
+      <property name="spacing">2</property>
+
+      <child internal-child="action_area">
+       <widget class="GtkHButtonBox" id="dialog-action_area">
+         <property name="visible">True</property>
+         <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+         <child>
+           <widget class="GtkButton" id="button_close">
+             <property name="visible">True</property>
+             <property name="can_default">True</property>
+             <property name="can_focus">True</property>
+             <property name="label">gtk-close</property>
+             <property name="use_stock">True</property>
+             <property name="relief">GTK_RELIEF_NORMAL</property>
+             <property name="focus_on_click">True</property>
+             <property name="response_id">-6</property>
+           </widget>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">False</property>
+         <property name="fill">True</property>
+         <property name="pack_type">GTK_PACK_END</property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkHBox" id="hbox146">
+         <property name="border_width">6</property>
+         <property name="visible">True</property>
+         <property name="homogeneous">False</property>
+         <property name="spacing">18</property>
+
+         <child>
+           <widget class="GtkVBox" id="vbox195">
+             <property name="visible">True</property>
+             <property name="homogeneous">False</property>
+             <property name="spacing">6</property>
+
+             <child>
+               <widget class="GtkScrolledWindow" id="scrolledwindow17">
+                 <property name="visible">True</property>
+                 <property name="can_focus">True</property>
+                 <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                 <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                 <property name="shadow_type">GTK_SHADOW_IN</property>
+                 <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+                 <child>
+                   <widget class="GtkTreeView" id="treeview">
+                     <property name="height_request">200</property>
+                     <property name="visible">True</property>
+                     <property name="can_focus">True</property>
+                     <property name="headers_visible">True</property>
+                     <property name="rules_hint">False</property>
+                     <property name="reorderable">False</property>
+                     <property name="enable_search">False</property>
+                     <property name="fixed_height_mode">False</property>
+                     <property name="hover_selection">False</property>
+                     <property name="hover_expand">False</property>
+                   </widget>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">True</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkVBox" id="vbox196">
+                 <property name="visible">True</property>
+                 <property name="homogeneous">False</property>
+                 <property name="spacing">6</property>
+
+                 <child>
+                   <widget class="GtkButton" id="button_connect">
+                     <property name="visible">True</property>
+                     <property name="can_focus">True</property>
+                     <property name="label">gtk-connect</property>
+                     <property name="use_stock">False</property>
+                     <property name="relief">GTK_RELIEF_NORMAL</property>
+                     <property name="focus_on_click">True</property>
+                   </widget>
+                   <packing>
+                     <property name="padding">0</property>
+                     <property name="expand">False</property>
+                     <property name="fill">False</property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkHBox" id="hbox148">
+                     <property name="visible">True</property>
+                     <property name="homogeneous">True</property>
+                     <property name="spacing">6</property>
+
+                     <child>
+                       <widget class="GtkButton" id="button_add">
+                         <property name="visible">True</property>
+                         <property name="can_focus">True</property>
+                         <property name="label">gtk-add</property>
+                         <property name="use_stock">True</property>
+                         <property name="relief">GTK_RELIEF_NORMAL</property>
+                         <property name="focus_on_click">True</property>
+                       </widget>
+                       <packing>
+                         <property name="padding">0</property>
+                         <property name="expand">True</property>
+                         <property name="fill">True</property>
+                       </packing>
+                     </child>
+
+                     <child>
+                       <widget class="GtkButton" id="button_remove">
+                         <property name="visible">True</property>
+                         <property name="can_focus">True</property>
+                         <property name="label">gtk-remove</property>
+                         <property name="use_stock">True</property>
+                         <property name="relief">GTK_RELIEF_NORMAL</property>
+                         <property name="focus_on_click">True</property>
+                       </widget>
+                       <packing>
+                         <property name="padding">0</property>
+                         <property name="expand">True</property>
+                         <property name="fill">True</property>
+                       </packing>
+                     </child>
+                   </widget>
+                   <packing>
+                     <property name="padding">0</property>
+                     <property name="expand">True</property>
+                     <property name="fill">True</property>
+                   </packing>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">False</property>
+                 <property name="fill">False</property>
+               </packing>
+             </child>
+           </widget>
+           <packing>
+             <property name="padding">0</property>
+             <property name="expand">False</property>
+             <property name="fill">False</property>
+           </packing>
+         </child>
+
+         <child>
+           <widget class="GtkVBox" id="vbox214">
+             <property name="width_request">415</property>
+             <property name="visible">True</property>
+             <property name="homogeneous">False</property>
+             <property name="spacing">18</property>
+
+             <child>
+               <widget class="GtkVBox" id="vbox_details">
+                 <property name="visible">True</property>
+                 <property name="homogeneous">False</property>
+                 <property name="spacing">18</property>
+
+                 <child>
+                   <widget class="GtkFrame" id="frame1">
+                     <property name="visible">True</property>
+                     <property name="label_xalign">0</property>
+                     <property name="label_yalign">0.5</property>
+                     <property name="shadow_type">GTK_SHADOW_NONE</property>
+
+                     <child>
+                       <widget class="GtkAlignment" id="alignment7">
+                         <property name="visible">True</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xscale">1</property>
+                         <property name="yscale">1</property>
+                         <property name="top_padding">6</property>
+                         <property name="bottom_padding">0</property>
+                         <property name="left_padding">20</property>
+                         <property name="right_padding">0</property>
+
+                         <child>
+                           <widget class="GtkVBox" id="vbox213">
+                             <property name="visible">True</property>
+                             <property name="homogeneous">False</property>
+                             <property name="spacing">6</property>
+
+                             <child>
+                               <widget class="GtkTable" id="table14">
+                                 <property name="visible">True</property>
+                                 <property name="n_rows">2</property>
+                                 <property name="n_columns">2</property>
+                                 <property name="homogeneous">False</property>
+                                 <property name="row_spacing">6</property>
+                                 <property name="column_spacing">6</property>
+
+                                 <child>
+                                   <widget class="GtkImage" id="image_type">
+                                     <property name="visible">True</property>
+                                     <property name="stock">gtk-cut</property>
+                                     <property name="icon_size">6</property>
+                                     <property name="xalign">0.5</property>
+                                     <property name="yalign">0</property>
+                                     <property name="xpad">0</property>
+                                     <property name="ypad">0</property>
+                                   </widget>
+                                   <packing>
+                                     <property name="left_attach">1</property>
+                                     <property name="right_attach">2</property>
+                                     <property name="top_attach">0</property>
+                                     <property name="bottom_attach">2</property>
+                                     <property name="x_options"></property>
+                                     <property name="y_options"></property>
+                                   </packing>
+                                 </child>
+
+                                 <child>
+                                   <widget class="GtkLabel" id="label_name">
+                                     <property name="visible">True</property>
+                                     <property name="label" translatable="yes">Imendio </property>
+                                     <property name="use_underline">False</property>
+                                     <property name="use_markup">False</property>
+                                     <property name="justify">GTK_JUSTIFY_LEFT</property>
+                                     <property name="wrap">False</property>
+                                     <property name="selectable">False</property>
+                                     <property name="xalign">0</property>
+                                     <property name="yalign">0.5</property>
+                                     <property name="xpad">0</property>
+                                     <property name="ypad">0</property>
+                                     <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+                                     <property name="width_chars">0</property>
+                                     <property name="single_line_mode">False</property>
+                                     <property name="angle">0</property>
+                                   </widget>
+                                   <packing>
+                                     <property name="left_attach">0</property>
+                                     <property name="right_attach">1</property>
+                                     <property name="top_attach">1</property>
+                                     <property name="bottom_attach">2</property>
+                                     <property name="y_options"></property>
+                                   </packing>
+                                 </child>
+
+                                 <child>
+                                   <widget class="GtkLabel" id="label_type">
+                                     <property name="visible">True</property>
+                                     <property name="label" translatable="yes">Jabber</property>
+                                     <property name="use_underline">False</property>
+                                     <property name="use_markup">False</property>
+                                     <property name="justify">GTK_JUSTIFY_LEFT</property>
+                                     <property name="wrap">False</property>
+                                     <property name="selectable">False</property>
+                                     <property name="xalign">0</property>
+                                     <property name="yalign">0.5</property>
+                                     <property name="xpad">0</property>
+                                     <property name="ypad">0</property>
+                                     <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+                                     <property name="width_chars">-1</property>
+                                     <property name="single_line_mode">False</property>
+                                     <property name="angle">0</property>
+                                   </widget>
+                                   <packing>
+                                     <property name="left_attach">0</property>
+                                     <property name="right_attach">1</property>
+                                     <property name="top_attach">0</property>
+                                     <property name="bottom_attach">1</property>
+                                     <property name="y_options"></property>
+                                   </packing>
+                                 </child>
+                               </widget>
+                               <packing>
+                                 <property name="padding">0</property>
+                                 <property name="expand">True</property>
+                                 <property name="fill">True</property>
+                               </packing>
+                             </child>
+                           </widget>
+                         </child>
+                       </widget>
+                     </child>
+
+                     <child>
+                       <widget class="GtkLabel" id="label598">
+                         <property name="visible">True</property>
+                         <property name="label" translatable="yes">&lt;b&gt;Account&lt;/b&gt;</property>
+                         <property name="use_underline">False</property>
+                         <property name="use_markup">True</property>
+                         <property name="justify">GTK_JUSTIFY_LEFT</property>
+                         <property name="wrap">False</property>
+                         <property name="selectable">False</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                         <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+                         <property name="width_chars">-1</property>
+                         <property name="single_line_mode">False</property>
+                         <property name="angle">0</property>
+                       </widget>
+                       <packing>
+                         <property name="type">label_item</property>
+                       </packing>
+                     </child>
+                   </widget>
+                   <packing>
+                     <property name="padding">0</property>
+                     <property name="expand">False</property>
+                     <property name="fill">False</property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkFrame" id="frame2">
+                     <property name="visible">True</property>
+                     <property name="label_xalign">0</property>
+                     <property name="label_yalign">0.5</property>
+                     <property name="shadow_type">GTK_SHADOW_NONE</property>
+
+                     <child>
+                       <widget class="GtkAlignment" id="alignment_settings">
+                         <property name="visible">True</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xscale">1</property>
+                         <property name="yscale">1</property>
+                         <property name="top_padding">6</property>
+                         <property name="bottom_padding">0</property>
+                         <property name="left_padding">20</property>
+                         <property name="right_padding">0</property>
+
+                         <child>
+                           <placeholder/>
+                         </child>
+                       </widget>
+                     </child>
+
+                     <child>
+                       <widget class="GtkLabel" id="label599">
+                         <property name="visible">True</property>
+                         <property name="label" translatable="yes">&lt;b&gt;Settings&lt;/b&gt;</property>
+                         <property name="use_underline">False</property>
+                         <property name="use_markup">True</property>
+                         <property name="justify">GTK_JUSTIFY_LEFT</property>
+                         <property name="wrap">False</property>
+                         <property name="selectable">False</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                         <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+                         <property name="width_chars">-1</property>
+                         <property name="single_line_mode">False</property>
+                         <property name="angle">0</property>
+                       </widget>
+                       <packing>
+                         <property name="type">label_item</property>
+                       </packing>
+                     </child>
+                   </widget>
+                   <packing>
+                     <property name="padding">0</property>
+                     <property name="expand">True</property>
+                     <property name="fill">True</property>
+                   </packing>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">True</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkFrame" id="frame_new_account">
+                 <property name="label_xalign">0</property>
+                 <property name="label_yalign">0.5</property>
+                 <property name="shadow_type">GTK_SHADOW_NONE</property>
+
+                 <child>
+                   <widget class="GtkAlignment" id="alignment29">
+                     <property name="visible">True</property>
+                     <property name="xalign">0.5</property>
+                     <property name="yalign">0.5</property>
+                     <property name="xscale">1</property>
+                     <property name="yscale">1</property>
+                     <property name="top_padding">6</property>
+                     <property name="bottom_padding">0</property>
+                     <property name="left_padding">20</property>
+                     <property name="right_padding">0</property>
+
+                     <child>
+                       <widget class="GtkVBox" id="vbox216">
+                         <property name="visible">True</property>
+                         <property name="homogeneous">False</property>
+                         <property name="spacing">12</property>
+
+                         <child>
+                           <widget class="GtkTable" id="table_new_account">
+                             <property name="visible">True</property>
+                             <property name="n_rows">2</property>
+                             <property name="n_columns">2</property>
+                             <property name="homogeneous">False</property>
+                             <property name="row_spacing">6</property>
+                             <property name="column_spacing">6</property>
+
+                             <child>
+                               <widget class="GtkLabel" id="label640">
+                                 <property name="visible">True</property>
+                                 <property name="label" translatable="yes">_Type:</property>
+                                 <property name="use_underline">True</property>
+                                 <property name="use_markup">False</property>
+                                 <property name="justify">GTK_JUSTIFY_LEFT</property>
+                                 <property name="wrap">False</property>
+                                 <property name="selectable">False</property>
+                                 <property name="xalign">0</property>
+                                 <property name="yalign">0.5</property>
+                                 <property name="xpad">0</property>
+                                 <property name="ypad">0</property>
+                                 <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+                                 <property name="width_chars">-1</property>
+                                 <property name="single_line_mode">False</property>
+                                 <property name="angle">0</property>
+                               </widget>
+                               <packing>
+                                 <property name="left_attach">0</property>
+                                 <property name="right_attach">1</property>
+                                 <property name="top_attach">0</property>
+                                 <property name="bottom_attach">1</property>
+                                 <property name="x_options"></property>
+                                 <property name="y_options"></property>
+                               </packing>
+                             </child>
+
+                             <child>
+                               <widget class="GtkLabel" id="label638">
+                                 <property name="visible">True</property>
+                                 <property name="label" translatable="yes">_Name:</property>
+                                 <property name="use_underline">True</property>
+                                 <property name="use_markup">False</property>
+                                 <property name="justify">GTK_JUSTIFY_LEFT</property>
+                                 <property name="wrap">False</property>
+                                 <property name="selectable">False</property>
+                                 <property name="xalign">0</property>
+                                 <property name="yalign">0.5</property>
+                                 <property name="xpad">0</property>
+                                 <property name="ypad">0</property>
+                                 <property name="mnemonic_widget">entry_name</property>
+                                 <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+                                 <property name="width_chars">-1</property>
+                                 <property name="single_line_mode">False</property>
+                                 <property name="angle">0</property>
+                               </widget>
+                               <packing>
+                                 <property name="left_attach">0</property>
+                                 <property name="right_attach">1</property>
+                                 <property name="top_attach">1</property>
+                                 <property name="bottom_attach">2</property>
+                                 <property name="x_options"></property>
+                                 <property name="y_options"></property>
+                               </packing>
+                             </child>
+
+                             <child>
+                               <widget class="GtkEntry" id="entry_name">
+                                 <property name="visible">True</property>
+                                 <property name="tooltip" translatable="yes">A unique name for this account to identify it personally to you.</property>
+                                 <property name="can_focus">True</property>
+                                 <property name="editable">True</property>
+                                 <property name="visibility">True</property>
+                                 <property name="max_length">0</property>
+                                 <property name="text" translatable="yes"></property>
+                                 <property name="has_frame">True</property>
+                                 <property name="invisible_char">*</property>
+                                 <property name="activates_default">False</property>
+                               </widget>
+                               <packing>
+                                 <property name="left_attach">1</property>
+                                 <property name="right_attach">2</property>
+                                 <property name="top_attach">1</property>
+                                 <property name="bottom_attach">2</property>
+                                 <property name="y_options"></property>
+                               </packing>
+                             </child>
+                           </widget>
+                           <packing>
+                             <property name="padding">0</property>
+                             <property name="expand">True</property>
+                             <property name="fill">True</property>
+                           </packing>
+                         </child>
+
+                         <child>
+                           <widget class="GtkHBox" id="hbox181">
+                             <property name="visible">True</property>
+                             <property name="homogeneous">False</property>
+                             <property name="spacing">6</property>
+
+                             <child>
+                               <widget class="GtkButton" id="button_create">
+                                 <property name="visible">True</property>
+                                 <property name="sensitive">False</property>
+                                 <property name="can_focus">True</property>
+                                 <property name="relief">GTK_RELIEF_NORMAL</property>
+                                 <property name="focus_on_click">True</property>
+
+                                 <child>
+                                   <widget class="GtkAlignment" id="alignment1">
+                                     <property name="visible">True</property>
+                                     <property name="xalign">0.5</property>
+                                     <property name="yalign">0.5</property>
+                                     <property name="xscale">0</property>
+                                     <property name="yscale">0</property>
+                                     <property name="top_padding">0</property>
+                                     <property name="bottom_padding">0</property>
+                                     <property name="left_padding">0</property>
+                                     <property name="right_padding">0</property>
+
+                                     <child>
+                                       <widget class="GtkHBox" id="hbox1">
+                                         <property name="visible">True</property>
+                                         <property name="homogeneous">False</property>
+                                         <property name="spacing">2</property>
+
+                                         <child>
+                                           <widget class="GtkImage" id="image1">
+                                             <property name="visible">True</property>
+                                             <property name="stock">gtk-new</property>
+                                             <property name="icon_size">4</property>
+                                             <property name="xalign">0.5</property>
+                                             <property name="yalign">0.5</property>
+                                             <property name="xpad">0</property>
+                                             <property name="ypad">0</property>
+                                           </widget>
+                                           <packing>
+                                             <property name="padding">0</property>
+                                             <property name="expand">False</property>
+                                             <property name="fill">False</property>
+                                           </packing>
+                                         </child>
+
+                                         <child>
+                                           <widget class="GtkLabel" id="label1">
+                                             <property name="visible">True</property>
+                                             <property name="label" translatable="yes">Cr_eate</property>
+                                             <property name="use_underline">True</property>
+                                             <property name="use_markup">False</property>
+                                             <property name="justify">GTK_JUSTIFY_LEFT</property>
+                                             <property name="wrap">False</property>
+                                             <property name="selectable">False</property>
+                                             <property name="xalign">0.5</property>
+                                             <property name="yalign">0.5</property>
+                                             <property name="xpad">0</property>
+                                             <property name="ypad">0</property>
+                                             <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+                                             <property name="width_chars">-1</property>
+                                             <property name="single_line_mode">False</property>
+                                             <property name="angle">0</property>
+                                           </widget>
+                                           <packing>
+                                             <property name="padding">0</property>
+                                             <property name="expand">False</property>
+                                             <property name="fill">False</property>
+                                           </packing>
+                                         </child>
+                                       </widget>
+                                     </child>
+                                   </widget>
+                                 </child>
+                               </widget>
+                               <packing>
+                                 <property name="padding">0</property>
+                                 <property name="expand">False</property>
+                                 <property name="fill">False</property>
+                                 <property name="pack_type">GTK_PACK_END</property>
+                               </packing>
+                             </child>
+
+                             <child>
+                               <widget class="GtkButton" id="button_back">
+                                 <property name="visible">True</property>
+                                 <property name="can_focus">True</property>
+                                 <property name="label">gtk-go-back</property>
+                                 <property name="use_stock">True</property>
+                                 <property name="relief">GTK_RELIEF_NORMAL</property>
+                                 <property name="focus_on_click">True</property>
+                               </widget>
+                               <packing>
+                                 <property name="padding">0</property>
+                                 <property name="expand">False</property>
+                                 <property name="fill">False</property>
+                                 <property name="pack_type">GTK_PACK_END</property>
+                               </packing>
+                             </child>
+                           </widget>
+                           <packing>
+                             <property name="padding">0</property>
+                             <property name="expand">False</property>
+                             <property name="fill">False</property>
+                             <property name="pack_type">GTK_PACK_END</property>
+                           </packing>
+                         </child>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkLabel" id="label643">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">&lt;b&gt;New Account&lt;/b&gt;</property>
+                     <property name="use_underline">False</property>
+                     <property name="use_markup">True</property>
+                     <property name="justify">GTK_JUSTIFY_LEFT</property>
+                     <property name="wrap">False</property>
+                     <property name="selectable">False</property>
+                     <property name="xalign">0.5</property>
+                     <property name="yalign">0.5</property>
+                     <property name="xpad">0</property>
+                     <property name="ypad">0</property>
+                     <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+                     <property name="width_chars">-1</property>
+                     <property name="single_line_mode">False</property>
+                     <property name="angle">0</property>
+                   </widget>
+                   <packing>
+                     <property name="type">label_item</property>
+                   </packing>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">False</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkFrame" id="frame_no_account">
+                 <property name="label_xalign">0</property>
+                 <property name="label_yalign">0.5</property>
+                 <property name="shadow_type">GTK_SHADOW_NONE</property>
+
+                 <child>
+                   <widget class="GtkAlignment" id="alignment21">
+                     <property name="visible">True</property>
+                     <property name="xalign">0.5</property>
+                     <property name="yalign">0.5</property>
+                     <property name="xscale">1</property>
+                     <property name="yscale">1</property>
+                     <property name="top_padding">6</property>
+                     <property name="bottom_padding">0</property>
+                     <property name="left_padding">12</property>
+                     <property name="right_padding">0</property>
+
+                     <child>
+                       <widget class="GtkLabel" id="label_no_account_blurb">
+                         <property name="visible">True</property>
+                         <property name="label" translatable="yes">To add a new account, you can click on the 'Add' button and a new entry will be created for you to started configuring.
+
+If you do not want to add an account, simply click on the account you want to configure in the list on the left.</property>
+                         <property name="use_underline">False</property>
+                         <property name="use_markup">True</property>
+                         <property name="justify">GTK_JUSTIFY_LEFT</property>
+                         <property name="wrap">True</property>
+                         <property name="selectable">False</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                         <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+                         <property name="width_chars">-1</property>
+                         <property name="single_line_mode">False</property>
+                         <property name="angle">0</property>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkLabel" id="label_no_account">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">&lt;b&gt;No Account Selected&lt;/b&gt;</property>
+                     <property name="use_underline">False</property>
+                     <property name="use_markup">True</property>
+                     <property name="justify">GTK_JUSTIFY_LEFT</property>
+                     <property name="wrap">False</property>
+                     <property name="selectable">False</property>
+                     <property name="xalign">0.5</property>
+                     <property name="yalign">0.5</property>
+                     <property name="xpad">0</property>
+                     <property name="ypad">0</property>
+                     <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+                     <property name="width_chars">-1</property>
+                     <property name="single_line_mode">False</property>
+                     <property name="angle">0</property>
+                   </widget>
+                   <packing>
+                     <property name="type">label_item</property>
+                   </packing>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">False</property>
+                 <property name="fill">False</property>
+               </packing>
+             </child>
+           </widget>
+           <packing>
+             <property name="padding">0</property>
+             <property name="expand">True</property>
+             <property name="fill">True</property>
+           </packing>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">True</property>
+         <property name="fill">True</property>
+       </packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
+</glade-interface>
diff --git a/libempathy-gtk/empathy-accounts-dialog.h b/libempathy-gtk/empathy-accounts-dialog.h
new file mode 100644 (file)
index 0000000..db800b9
--- /dev/null
@@ -0,0 +1,35 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2005-2007 Imendio AB
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * 
+ * Authors: Martyn Russell <martyn@imendio.com>
+ */
+
+#ifndef __EMPATHY_ACCOUNTS_DIALOG_H__
+#define __EMPATHY_ACCOUNTS_DIALOG_H__
+
+#include <gtk/gtkwidget.h>
+
+G_BEGIN_DECLS
+
+GtkWidget *empathy_accounts_dialog_show (GtkWindow *parent);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_ACCOUNTS_DIALOG_H__ */
diff --git a/libempathy-gtk/empathy-cell-renderer-expander.c b/libempathy-gtk/empathy-cell-renderer-expander.c
new file mode 100644 (file)
index 0000000..51930ab
--- /dev/null
@@ -0,0 +1,482 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2006-2007 Imendio AB
+ *
+ * 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * 
+ * Authors: Kristian Rietveld <kris@imendio.com>
+ */
+
+/* To do:
+ *  - should probably cancel animation if model changes
+ *  - need to handle case where node-in-animation is removed
+ *  - it only handles a single animation at a time; but I guess users
+ *    aren't fast enough to trigger two or more animations at once anyway :P
+ *    (could guard for this by just cancelling the "old" animation, and
+ *     start the new one).
+ */
+
+#include <gtk/gtktreeview.h>
+
+#include "empathy-cell-renderer-expander.h"
+
+#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_CELL_RENDERER_EXPANDER, EmpathyCellRendererExpanderPriv))
+
+static void     empathy_cell_renderer_expander_init         (EmpathyCellRendererExpander      *expander);
+static void     empathy_cell_renderer_expander_class_init   (EmpathyCellRendererExpanderClass *klass);
+static void     empathy_cell_renderer_expander_get_property (GObject                         *object,
+                                                           guint                            param_id,
+                                                           GValue                          *value,
+                                                           GParamSpec                      *pspec);
+static void     empathy_cell_renderer_expander_set_property (GObject                         *object,
+                                                           guint                            param_id,
+                                                           const GValue                    *value,
+                                                           GParamSpec                      *pspec);
+static void     empathy_cell_renderer_expander_finalize     (GObject                         *object);
+static void     empathy_cell_renderer_expander_get_size     (GtkCellRenderer                 *cell,
+                                                           GtkWidget                       *widget,
+                                                           GdkRectangle                    *cell_area,
+                                                           gint                            *x_offset,
+                                                           gint                            *y_offset,
+                                                           gint                            *width,
+                                                           gint                            *height);
+static void     empathy_cell_renderer_expander_render       (GtkCellRenderer                 *cell,
+                                                           GdkWindow                       *window,
+                                                           GtkWidget                       *widget,
+                                                           GdkRectangle                    *background_area,
+                                                           GdkRectangle                    *cell_area,
+                                                           GdkRectangle                    *expose_area,
+                                                           GtkCellRendererState             flags);
+static gboolean empathy_cell_renderer_expander_activate     (GtkCellRenderer                 *cell,
+                                                           GdkEvent                        *event,
+                                                           GtkWidget                       *widget,
+                                                           const gchar                     *path,
+                                                           GdkRectangle                    *background_area,
+                                                           GdkRectangle                    *cell_area,
+                                                           GtkCellRendererState             flags);
+
+enum {
+       PROP_0,
+       PROP_EXPANDER_STYLE,
+       PROP_EXPANDER_SIZE,
+       PROP_ACTIVATABLE
+};
+
+typedef struct _EmpathyCellRendererExpanderPriv EmpathyCellRendererExpanderPriv;
+
+struct _EmpathyCellRendererExpanderPriv {
+       GtkExpanderStyle     expander_style;
+       gint                 expander_size;
+
+       GtkTreeView         *animation_view;
+       GtkTreeRowReference *animation_node;
+       GtkExpanderStyle     animation_style;
+       guint                animation_timeout;
+       GdkRectangle         animation_area;
+
+       guint                activatable : 1;
+       guint                animation_expanding : 1;
+};
+
+G_DEFINE_TYPE (EmpathyCellRendererExpander, empathy_cell_renderer_expander, GTK_TYPE_CELL_RENDERER)
+
+static void
+empathy_cell_renderer_expander_init (EmpathyCellRendererExpander *expander)
+{
+       EmpathyCellRendererExpanderPriv *priv;
+
+       priv = GET_PRIV (expander);
+
+       priv->expander_style = GTK_EXPANDER_COLLAPSED;
+       priv->expander_size = 12;
+       priv->activatable = TRUE;
+       priv->animation_node = NULL;
+
+       GTK_CELL_RENDERER (expander)->xpad = 2;
+       GTK_CELL_RENDERER (expander)->ypad = 2;
+       GTK_CELL_RENDERER (expander)->mode = GTK_CELL_RENDERER_MODE_ACTIVATABLE;
+}
+
+static void
+empathy_cell_renderer_expander_class_init (EmpathyCellRendererExpanderClass *klass)
+{
+       GObjectClass         *object_class;
+       GtkCellRendererClass *cell_class;
+
+       object_class  = G_OBJECT_CLASS (klass);
+       cell_class = GTK_CELL_RENDERER_CLASS (klass);
+
+       object_class->finalize = empathy_cell_renderer_expander_finalize;
+
+       object_class->get_property = empathy_cell_renderer_expander_get_property;
+       object_class->set_property = empathy_cell_renderer_expander_set_property;
+
+       cell_class->get_size = empathy_cell_renderer_expander_get_size;
+       cell_class->render = empathy_cell_renderer_expander_render;
+       cell_class->activate = empathy_cell_renderer_expander_activate;
+
+       g_object_class_install_property (object_class,
+                                        PROP_EXPANDER_STYLE,
+                                        g_param_spec_enum ("expander-style",
+                                                           "Expander Style",
+                                                           "Style to use when painting the expander",
+                                                           GTK_TYPE_EXPANDER_STYLE,
+                                                           GTK_EXPANDER_COLLAPSED,
+                                                           G_PARAM_READWRITE));
+
+       g_object_class_install_property (object_class,
+                                        PROP_EXPANDER_SIZE,
+                                        g_param_spec_int ("expander-size",
+                                                          "Expander Size",
+                                                          "The size of the expander",
+                                                          0,
+                                                          G_MAXINT,
+                                                          12,
+                                                          G_PARAM_READWRITE));
+
+       g_object_class_install_property (object_class,
+                                        PROP_ACTIVATABLE,
+                                        g_param_spec_boolean ("activatable",
+                                                              "Activatable",
+                                                              "The expander can be activated",
+                                                              TRUE,
+                                                              G_PARAM_READWRITE));
+
+       g_type_class_add_private (object_class, sizeof (EmpathyCellRendererExpanderPriv));
+}
+
+static void
+empathy_cell_renderer_expander_get_property (GObject    *object,
+                                           guint       param_id,
+                                           GValue     *value,
+                                           GParamSpec *pspec)
+{
+       EmpathyCellRendererExpander     *expander;
+       EmpathyCellRendererExpanderPriv *priv;
+
+       expander = EMPATHY_CELL_RENDERER_EXPANDER (object);
+       priv = GET_PRIV (expander);
+
+       switch (param_id) {
+       case PROP_EXPANDER_STYLE:
+               g_value_set_enum (value, priv->expander_style);
+               break;
+
+       case PROP_EXPANDER_SIZE:
+               g_value_set_int (value, priv->expander_size);
+               break;
+
+       case PROP_ACTIVATABLE:
+               g_value_set_boolean (value, priv->activatable);
+               break;
+
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+               break;
+       }
+}
+
+static void
+empathy_cell_renderer_expander_set_property (GObject      *object,
+                                           guint         param_id,
+                                           const GValue *value,
+                                           GParamSpec   *pspec)
+{
+       EmpathyCellRendererExpander     *expander;
+       EmpathyCellRendererExpanderPriv *priv;
+
+       expander = EMPATHY_CELL_RENDERER_EXPANDER (object);
+       priv = GET_PRIV (expander);
+
+       switch (param_id) {
+       case PROP_EXPANDER_STYLE:
+               priv->expander_style = g_value_get_enum (value);
+               break;
+
+       case PROP_EXPANDER_SIZE:
+               priv->expander_size = g_value_get_int (value);
+               break;
+
+       case PROP_ACTIVATABLE:
+               priv->activatable = g_value_get_boolean (value);
+               break;
+
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+               break;
+       }
+}
+
+static void
+empathy_cell_renderer_expander_finalize (GObject *object)
+{
+       EmpathyCellRendererExpanderPriv *priv;
+
+       priv = GET_PRIV (object);
+
+       if (priv->animation_timeout) {
+               g_source_remove (priv->animation_timeout);
+               priv->animation_timeout = 0;
+       }
+
+       if (priv->animation_node) {
+               gtk_tree_row_reference_free (priv->animation_node);
+       }
+
+       (* G_OBJECT_CLASS (empathy_cell_renderer_expander_parent_class)->finalize) (object);
+}
+
+GtkCellRenderer *
+empathy_cell_renderer_expander_new (void)
+{
+       return g_object_new (EMPATHY_TYPE_CELL_RENDERER_EXPANDER, NULL);
+}
+
+static void
+empathy_cell_renderer_expander_get_size (GtkCellRenderer *cell,
+                                       GtkWidget       *widget,
+                                       GdkRectangle    *cell_area,
+                                       gint            *x_offset,
+                                       gint            *y_offset,
+                                       gint            *width,
+                                       gint            *height)
+{
+       EmpathyCellRendererExpander     *expander;
+       EmpathyCellRendererExpanderPriv *priv;
+
+       expander = (EmpathyCellRendererExpander*) cell;
+       priv = GET_PRIV (expander);
+
+       if (cell_area) {
+               if (x_offset) {
+                       *x_offset = cell->xalign * (cell_area->width - (priv->expander_size + (2 * cell->xpad)));
+                       *x_offset = MAX (*x_offset, 0);
+               }
+
+               if (y_offset) {
+                       *y_offset = cell->yalign * (cell_area->height - (priv->expander_size + (2 * cell->ypad)));
+                       *y_offset = MAX (*y_offset, 0);
+               }
+       } else {
+               if (x_offset)
+                       *x_offset = 0;
+
+               if (y_offset)
+                       *y_offset = 0;
+       }
+
+       if (width)
+               *width = cell->xpad * 2 + priv->expander_size;
+
+       if (height)
+               *height = cell->ypad * 2 + priv->expander_size;
+}
+
+static void
+empathy_cell_renderer_expander_render (GtkCellRenderer      *cell,
+                                     GdkWindow            *window,
+                                     GtkWidget            *widget,
+                                     GdkRectangle         *background_area,
+                                     GdkRectangle         *cell_area,
+                                     GdkRectangle         *expose_area,
+                                     GtkCellRendererState  flags)
+{
+       EmpathyCellRendererExpander     *expander;
+       EmpathyCellRendererExpanderPriv *priv;
+       GtkExpanderStyle                expander_style;
+       gint                            x_offset, y_offset;
+
+       expander = (EmpathyCellRendererExpander*) cell;
+       priv = GET_PRIV (expander);
+
+       if (priv->animation_node) {
+               GtkTreePath *path;
+               GdkRectangle rect;
+
+               /* Not sure if I like this ... */
+               path = gtk_tree_row_reference_get_path (priv->animation_node);
+               gtk_tree_view_get_background_area (priv->animation_view, path,
+                                                  NULL, &rect);
+               gtk_tree_path_free (path);
+
+               if (background_area->y == rect.y)
+                       expander_style = priv->animation_style;
+               else
+                       expander_style = priv->expander_style;
+       } else
+               expander_style = priv->expander_style;
+
+       empathy_cell_renderer_expander_get_size (cell, widget, cell_area,
+                                               &x_offset, &y_offset,
+                                               NULL, NULL);
+
+       gtk_paint_expander (widget->style,
+                           window,
+                           GTK_STATE_NORMAL,
+                           expose_area,
+                           widget,
+                           "treeview",
+                           cell_area->x + x_offset + cell->xpad + priv->expander_size / 2,
+                           cell_area->y + y_offset + cell->ypad + priv->expander_size / 2,
+                           expander_style);
+}
+
+static void
+invalidate_node (GtkTreeView *tree_view,
+                GtkTreePath *path)
+{
+       GdkWindow    *bin_window;
+       GdkRectangle  rect;
+
+       bin_window = gtk_tree_view_get_bin_window (tree_view);
+
+       gtk_tree_view_get_background_area (tree_view, path, NULL, &rect);
+
+       rect.x = 0;
+       rect.width = GTK_WIDGET (tree_view)->allocation.width;
+
+       gdk_window_invalidate_rect (bin_window, &rect, TRUE);
+}
+
+static gboolean
+do_animation (EmpathyCellRendererExpander *expander)
+{
+       EmpathyCellRendererExpanderPriv *priv;
+       GtkTreePath                    *path;
+       gboolean                        done = FALSE;
+
+       priv = GET_PRIV (expander);
+
+       if (priv->animation_expanding) {
+               if (priv->animation_style == GTK_EXPANDER_SEMI_COLLAPSED)
+                       priv->animation_style = GTK_EXPANDER_SEMI_EXPANDED;
+               else if (priv->animation_style == GTK_EXPANDER_SEMI_EXPANDED) {
+                       priv->animation_style = GTK_EXPANDER_EXPANDED;
+                       done = TRUE;
+               }
+       } else {
+               if (priv->animation_style == GTK_EXPANDER_SEMI_EXPANDED)
+                       priv->animation_style = GTK_EXPANDER_SEMI_COLLAPSED;
+               else if (priv->animation_style == GTK_EXPANDER_SEMI_COLLAPSED) {
+                       priv->animation_style = GTK_EXPANDER_COLLAPSED;
+                       done = TRUE;
+               }
+       }
+
+       path = gtk_tree_row_reference_get_path (priv->animation_node);
+       invalidate_node (priv->animation_view, path);
+       gtk_tree_path_free (path);
+
+       if (done) {
+               gtk_tree_row_reference_free (priv->animation_node);
+               priv->animation_node = NULL;
+               priv->animation_timeout = 0;
+       }
+
+       return !done;
+}
+
+static gboolean
+animation_timeout (gpointer data)
+{
+       gboolean retval;
+
+       GDK_THREADS_ENTER ();
+
+       retval = do_animation (data);
+
+       GDK_THREADS_LEAVE ();
+
+       return retval;
+}
+
+static void
+empathy_cell_renderer_expander_start_animation (EmpathyCellRendererExpander *expander,
+                                              GtkTreeView                *tree_view,
+                                              GtkTreePath                *path,
+                                              gboolean                    expanding,
+                                              GdkRectangle               *background_area)
+{
+       EmpathyCellRendererExpanderPriv *priv;
+
+       priv = GET_PRIV (expander);
+
+       if (expanding) {
+               priv->animation_style = GTK_EXPANDER_SEMI_COLLAPSED;
+       } else {
+               priv->animation_style = GTK_EXPANDER_SEMI_EXPANDED;
+       }
+
+       invalidate_node (tree_view, path);
+
+       priv->animation_expanding = expanding;
+       priv->animation_view = tree_view;
+       priv->animation_node = gtk_tree_row_reference_new (gtk_tree_view_get_model (tree_view), path);
+       priv->animation_timeout = g_timeout_add (50, animation_timeout, expander);
+}
+
+static gboolean
+empathy_cell_renderer_expander_activate (GtkCellRenderer      *cell,
+                                       GdkEvent             *event,
+                                       GtkWidget            *widget,
+                                       const gchar          *path_string,
+                                       GdkRectangle         *background_area,
+                                       GdkRectangle         *cell_area,
+                                       GtkCellRendererState  flags)
+{
+       EmpathyCellRendererExpander     *expander;
+       EmpathyCellRendererExpanderPriv *priv;
+       GtkTreePath                    *path;
+       gboolean                        animate;
+       gboolean                        expanding;
+
+       expander = EMPATHY_CELL_RENDERER_EXPANDER (cell);
+       priv = GET_PRIV (cell);
+
+       if (!GTK_IS_TREE_VIEW (widget) || !priv->activatable)
+               return FALSE;
+
+       path = gtk_tree_path_new_from_string (path_string);
+
+       if (gtk_tree_path_get_depth (path) > 1) {
+               gtk_tree_path_free (path);
+               return TRUE;
+       }
+
+       g_object_get (gtk_widget_get_settings (GTK_WIDGET (widget)),
+                     "gtk-enable-animations", &animate,
+                     NULL);
+
+       if (gtk_tree_view_row_expanded (GTK_TREE_VIEW (widget), path)) {
+               gtk_tree_view_collapse_row (GTK_TREE_VIEW (widget), path);
+               expanding = FALSE;
+       } else {
+               gtk_tree_view_expand_row (GTK_TREE_VIEW (widget), path, FALSE);
+               expanding = TRUE;
+       }
+
+       if (animate) {
+               empathy_cell_renderer_expander_start_animation (expander,
+                                                              GTK_TREE_VIEW (widget),
+                                                              path,
+                                                              expanding,
+                                                              background_area);
+       }
+
+       gtk_tree_path_free (path);
+
+       return TRUE;
+}
diff --git a/libempathy-gtk/empathy-cell-renderer-expander.h b/libempathy-gtk/empathy-cell-renderer-expander.h
new file mode 100644 (file)
index 0000000..d7e5f74
--- /dev/null
@@ -0,0 +1,59 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2006-2007 Imendio AB
+ *
+ * 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * 
+ * Authors: Kristian Rietveld <kris@imendio.com>
+ */
+
+#ifndef __EMPATHY_CELL_RENDERER_EXPANDER_H__
+#define __EMPATHY_CELL_RENDERER_EXPANDER_H__
+
+#include <gtk/gtkcellrenderer.h>
+
+G_BEGIN_DECLS
+
+#define EMPATHY_TYPE_CELL_RENDERER_EXPANDER            (empathy_cell_renderer_expander_get_type ())
+#define EMPATHY_CELL_RENDERER_EXPANDER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), EMPATHY_TYPE_CELL_RENDERER_EXPANDER, EmpathyCellRendererExpander))
+#define EMPATHY_CELL_RENDERER_EXPANDER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), EMPATHY_TYPE_CELL_RENDERER_EXPANDER, EmpathyCellRendererExpanderClass))
+#define EMPATHY_IS_CELL_RENDERER_EXPANDER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EMPATHY_TYPE_CELL_RENDERER_EXPANDER))
+#define EMPATHY_IS_CELL_RENDERER_EXPANDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EMPATHY_TYPE_CELL_RENDERER_EXPANDER))
+#define EMPATHY_CELL_RENDERER_EXPANDER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), EMPATHY_TYPE_CELL_RENDERER_EXPANDER, EmpathyCellRendererExpanderClass))
+
+typedef struct _EmpathyCellRendererExpander EmpathyCellRendererExpander;
+typedef struct _EmpathyCellRendererExpanderClass EmpathyCellRendererExpanderClass;
+
+struct _EmpathyCellRendererExpander {
+  GtkCellRenderer parent;
+};
+
+struct _EmpathyCellRendererExpanderClass {
+  GtkCellRendererClass parent_class;
+
+  /* Padding for future expansion */
+  void (*_gtk_reserved1) (void);
+  void (*_gtk_reserved2) (void);
+  void (*_gtk_reserved3) (void);
+  void (*_gtk_reserved4) (void);
+};
+
+GType            empathy_cell_renderer_expander_get_type (void) G_GNUC_CONST;
+GtkCellRenderer *empathy_cell_renderer_expander_new      (void);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_CELL_RENDERER_EXPANDER_H__ */
diff --git a/libempathy-gtk/empathy-cell-renderer-text.c b/libempathy-gtk/empathy-cell-renderer-text.c
new file mode 100644 (file)
index 0000000..d48de32
--- /dev/null
@@ -0,0 +1,368 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2004-2007 Imendio AB
+ *
+ * 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * 
+ * Authors: Mikael Hallendal <micke@imendio.com>
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "empathy-cell-renderer-text.h"
+
+#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_CELL_RENDERER_TEXT, EmpathyCellRendererTextPriv))
+
+struct _EmpathyCellRendererTextPriv {
+       gchar    *name;
+       gchar    *status;
+       gboolean  is_group;
+
+       gboolean  is_valid;
+       gboolean  is_selected;
+
+       gboolean  show_status;
+};
+
+static void empathy_cell_renderer_text_class_init (EmpathyCellRendererTextClass *klass);
+static void empathy_cell_renderer_text_init       (EmpathyCellRendererText      *cell);
+static void cell_renderer_text_finalize          (GObject                     *object);
+static void cell_renderer_text_get_property      (GObject                     *object,
+                                                 guint                        param_id,
+                                                 GValue                      *value,
+                                                 GParamSpec                  *pspec);
+static void cell_renderer_text_set_property      (GObject                     *object,
+                                                 guint                        param_id,
+                                                 const GValue                *value,
+                                                 GParamSpec                  *pspec);
+static void cell_renderer_text_get_size          (GtkCellRenderer             *cell,
+                                                 GtkWidget                   *widget,
+                                                 GdkRectangle                *cell_area,
+                                                 gint                        *x_offset,
+                                                 gint                        *y_offset,
+                                                 gint                        *width,
+                                                 gint                        *height);
+static void cell_renderer_text_render            (GtkCellRenderer             *cell,
+                                                 GdkDrawable                 *window,
+                                                 GtkWidget                   *widget,
+                                                 GdkRectangle                *background_area,
+                                                 GdkRectangle                *cell_area,
+                                                 GdkRectangle                *expose_area,
+                                                 GtkCellRendererState         flags);
+static void cell_renderer_text_update_text       (EmpathyCellRendererText      *cell,
+                                                 GtkWidget                   *widget,
+                                                 gboolean                     selected);
+
+/* Properties */
+enum {
+       PROP_0,
+       PROP_NAME,
+       PROP_STATUS,
+       PROP_IS_GROUP,
+       PROP_SHOW_STATUS,
+};
+
+G_DEFINE_TYPE (EmpathyCellRendererText, empathy_cell_renderer_text, GTK_TYPE_CELL_RENDERER_TEXT);
+
+static void
+empathy_cell_renderer_text_class_init (EmpathyCellRendererTextClass *klass)
+{
+       GObjectClass         *object_class;
+       GtkCellRendererClass *cell_class;
+
+       object_class = G_OBJECT_CLASS (klass);
+       cell_class = GTK_CELL_RENDERER_CLASS (klass);
+
+       object_class->finalize = cell_renderer_text_finalize;
+
+       object_class->get_property = cell_renderer_text_get_property;
+       object_class->set_property = cell_renderer_text_set_property;
+
+       cell_class->get_size = cell_renderer_text_get_size;
+       cell_class->render = cell_renderer_text_render;
+
+       g_object_class_install_property (object_class,
+                                        PROP_NAME,
+                                        g_param_spec_string ("name",
+                                                             "Name",
+                                                             "Contact name",
+                                                             NULL,
+                                                             G_PARAM_READWRITE));
+       g_object_class_install_property (object_class,
+                                        PROP_STATUS,
+                                        g_param_spec_string ("status",
+                                                             "Status",
+                                                             "Contact status string",
+                                                             NULL,
+                                                             G_PARAM_READWRITE));
+       g_object_class_install_property (object_class,
+                                        PROP_IS_GROUP,
+                                        g_param_spec_boolean ("is_group",
+                                                              "Is group",
+                                                              "Whether this cell is a group",
+                                                              FALSE,
+                                                              G_PARAM_READWRITE));
+       g_object_class_install_property (object_class,
+                                        PROP_SHOW_STATUS,
+                                        g_param_spec_boolean ("show-status",
+                                                              "Show status",
+                                                              "Whether to show the status line",
+                                                              TRUE,
+                                                              G_PARAM_READWRITE));
+
+       g_type_class_add_private (object_class, sizeof (EmpathyCellRendererTextPriv));
+}
+
+static void
+empathy_cell_renderer_text_init (EmpathyCellRendererText *cell)
+{
+       EmpathyCellRendererTextPriv *priv;
+
+       priv = GET_PRIV (cell);
+
+       g_object_set (cell,
+                     "ellipsize", PANGO_ELLIPSIZE_END,
+                     NULL);
+
+       priv->name = g_strdup ("");
+       priv->status = g_strdup ("");
+       priv->show_status = TRUE;
+}
+
+static void
+cell_renderer_text_finalize (GObject *object)
+{
+       EmpathyCellRendererText     *cell;
+       EmpathyCellRendererTextPriv *priv;
+
+       cell = EMPATHY_CELL_RENDERER_TEXT (object);
+       priv = GET_PRIV (cell);
+
+       g_free (priv->name);
+       g_free (priv->status);
+
+       (G_OBJECT_CLASS (empathy_cell_renderer_text_parent_class)->finalize) (object);
+}
+
+static void
+cell_renderer_text_get_property (GObject    *object,
+                                guint       param_id,
+                                GValue     *value,
+                                GParamSpec *pspec)
+{
+       EmpathyCellRendererText     *cell;
+       EmpathyCellRendererTextPriv *priv;
+
+       cell = EMPATHY_CELL_RENDERER_TEXT (object);
+       priv = GET_PRIV (cell);
+
+       switch (param_id) {
+       case PROP_NAME:
+               g_value_set_string (value, priv->name);
+               break;
+       case PROP_STATUS:
+               g_value_set_string (value, priv->status);
+               break;
+       case PROP_IS_GROUP:
+               g_value_set_boolean (value, priv->is_group);
+               break;
+       case PROP_SHOW_STATUS:
+               g_value_set_boolean (value, priv->show_status);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+               break;
+       }
+}
+
+static void
+cell_renderer_text_set_property (GObject      *object,
+                                guint         param_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+       EmpathyCellRendererText     *cell;
+       EmpathyCellRendererTextPriv *priv;
+       const gchar                *str;
+
+       cell = EMPATHY_CELL_RENDERER_TEXT (object);
+       priv = GET_PRIV (cell);
+
+       switch (param_id) {
+       case PROP_NAME:
+               g_free (priv->name);
+               str = g_value_get_string (value);
+               priv->name = g_strdup (str ? str : "");
+               g_strdelimit (priv->name, "\n\r\t", ' ');
+               priv->is_valid = FALSE;
+               break;
+       case PROP_STATUS:
+               g_free (priv->status);
+               str = g_value_get_string (value);
+               priv->status = g_strdup (str ? str : "");
+               g_strdelimit (priv->status, "\n\r\t", ' ');
+               priv->is_valid = FALSE;
+               break;
+       case PROP_IS_GROUP:
+               priv->is_group = g_value_get_boolean (value);
+               priv->is_valid = FALSE;
+               break;
+       case PROP_SHOW_STATUS:
+               priv->show_status = g_value_get_boolean (value);
+               priv->is_valid = FALSE;
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+               break;
+       }
+}
+
+static void
+cell_renderer_text_get_size (GtkCellRenderer *cell,
+                            GtkWidget       *widget,
+                            GdkRectangle    *cell_area,
+                            gint            *x_offset,
+                            gint            *y_offset,
+                            gint            *width,
+                            gint            *height)
+{
+       EmpathyCellRendererText     *celltext;
+       EmpathyCellRendererTextPriv *priv;
+
+       celltext = EMPATHY_CELL_RENDERER_TEXT (cell);
+       priv = GET_PRIV (cell);
+
+       /* Only update if not already valid so we get the right size. */
+       cell_renderer_text_update_text (celltext, widget, priv->is_selected);
+
+       (GTK_CELL_RENDERER_CLASS (empathy_cell_renderer_text_parent_class)->get_size) (cell, widget,
+                                                                                     cell_area,
+                                                                                     x_offset, y_offset,
+                                                                                     width, height);
+}
+
+static void
+cell_renderer_text_render (GtkCellRenderer      *cell,
+                          GdkWindow            *window,
+                          GtkWidget            *widget,
+                          GdkRectangle         *background_area,
+                          GdkRectangle         *cell_area,
+                          GdkRectangle         *expose_area,
+                          GtkCellRendererState  flags)
+{
+       EmpathyCellRendererText *celltext;
+
+       celltext = EMPATHY_CELL_RENDERER_TEXT (cell);
+
+       cell_renderer_text_update_text (celltext,
+                                       widget,
+                                       (flags & GTK_CELL_RENDERER_SELECTED));
+
+       (GTK_CELL_RENDERER_CLASS (empathy_cell_renderer_text_parent_class)->render) (
+               cell, window,
+               widget,
+               background_area,
+               cell_area,
+               expose_area, flags);
+}
+
+static void
+cell_renderer_text_update_text (EmpathyCellRendererText *cell,
+                               GtkWidget              *widget,
+                               gboolean                selected)
+{
+       EmpathyCellRendererTextPriv *priv;
+       PangoAttrList              *attr_list;
+       PangoAttribute             *attr_color, *attr_style, *attr_size;
+       GtkStyle                   *style;
+       gchar                      *str;
+
+       priv = GET_PRIV (cell);
+
+       if (priv->is_valid && priv->is_selected == selected) {
+               return;
+       }
+
+       if (priv->is_group) {
+               g_object_set (cell,
+                             "visible", TRUE,
+                             "weight", PANGO_WEIGHT_BOLD,
+                             "text", priv->name,
+                             "attributes", NULL,
+                             "xpad", 1,
+                             "ypad", 1,
+                             NULL);
+
+               priv->is_selected = selected;
+               priv->is_valid = TRUE;
+               return;
+       }
+
+       style = gtk_widget_get_style (widget);
+
+       attr_list = pango_attr_list_new ();
+
+       attr_style = pango_attr_style_new (PANGO_STYLE_ITALIC);
+       attr_style->start_index = strlen (priv->name) + 1;
+       attr_style->end_index = -1;
+       pango_attr_list_insert (attr_list, attr_style);
+
+       if (!selected) {
+               GdkColor color;
+
+               color = style->text_aa[GTK_STATE_NORMAL];
+
+               attr_color = pango_attr_foreground_new (color.red, color.green, color.blue);
+               attr_color->start_index = attr_style->start_index;
+               attr_color->end_index = -1;
+               pango_attr_list_insert (attr_list, attr_color);
+       }
+
+       attr_size = pango_attr_size_new (pango_font_description_get_size (style->font_desc) / 1.2);
+
+       attr_size->start_index = attr_style->start_index;
+       attr_size->end_index = -1;
+       pango_attr_list_insert (attr_list, attr_size);
+
+       if (!priv->status || !priv->status[0] || !priv->show_status) {
+               str = g_strdup (priv->name);
+       } else {
+               str = g_strdup_printf ("%s\n%s", priv->name, priv->status);
+       }
+
+       g_object_set (cell,
+                     "visible", TRUE,
+                     "weight", PANGO_WEIGHT_NORMAL,
+                     "text", str,
+                     "attributes", attr_list,
+                     "xpad", 0,
+                     "ypad", 1,
+                     NULL);
+
+       g_free (str);
+       pango_attr_list_unref (attr_list);
+
+       priv->is_selected = selected;
+       priv->is_valid = TRUE;
+}
+
+GtkCellRenderer *
+empathy_cell_renderer_text_new (void)
+{
+       return g_object_new (EMPATHY_TYPE_CELL_RENDERER_TEXT, NULL);
+}
diff --git a/libempathy-gtk/empathy-cell-renderer-text.h b/libempathy-gtk/empathy-cell-renderer-text.h
new file mode 100644 (file)
index 0000000..76cef31
--- /dev/null
@@ -0,0 +1,56 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2004-2007 Imendio AB
+ *
+ * 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * 
+ * Authors: Mikael Hallendal <micke@imendio.com>
+ */
+
+#ifndef __EMPATHY_CELL_RENDERER_TEXT_H__
+#define __EMPATHY_CELL_RENDERER_TEXT_H__
+
+#include <gtk/gtkcellrenderertext.h>
+
+G_BEGIN_DECLS
+
+#define EMPATHY_TYPE_CELL_RENDERER_TEXT         (empathy_cell_renderer_text_get_type ())
+#define EMPATHY_CELL_RENDERER_TEXT(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_CELL_RENDERER_TEXT, EmpathyCellRendererText))
+#define EMPATHY_CELL_RENDERER_TEXT_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), EMPATHY_TYPE_CELL_RENDERER_TEXT, EmpathyCellRendererTextClass))
+#define EMPATHY_IS_CELL_RENDERER_TEXT(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_CELL_RENDERER_TEXT))
+#define EMPATHY_IS_CELL_RENDERER_TEXT_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_CELL_RENDERER_TEXT))
+#define EMPATHY_CELL_RENDERER_TEXT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_CELL_RENDERER_TEXT, EmpathyCellRendererTextClass))
+
+typedef struct _EmpathyCellRendererText      EmpathyCellRendererText;
+typedef struct _EmpathyCellRendererTextClass EmpathyCellRendererTextClass;
+typedef struct _EmpathyCellRendererTextPriv  EmpathyCellRendererTextPriv;
+
+struct _EmpathyCellRendererText {
+       GtkCellRendererText         parent;
+
+       EmpathyCellRendererTextPriv *priv;
+};
+
+struct _EmpathyCellRendererTextClass {
+       GtkCellRendererTextClass    parent_class;
+};
+
+GType             empathy_cell_renderer_text_get_type (void) G_GNUC_CONST;
+GtkCellRenderer * empathy_cell_renderer_text_new      (void);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_CELL_RENDERER_TEXT_H__ */
diff --git a/libempathy-gtk/empathy-chat-view.c b/libempathy-gtk/empathy-chat-view.c
new file mode 100644 (file)
index 0000000..fda2686
--- /dev/null
@@ -0,0 +1,2226 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2002-2007 Imendio AB
+ *
+ * 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * 
+ * Authors: Mikael Hallendal <micke@imendio.com>
+ *          Richard Hult <richard@imendio.com>
+ *          Martyn Russell <martyn@imendio.com>
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <string.h>
+#include <time.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtkbutton.h>
+#include <gtk/gtkimage.h>
+#include <gtk/gtkmenu.h>
+#include <gtk/gtkmenuitem.h>
+#include <gtk/gtkimagemenuitem.h>
+#include <gtk/gtkstock.h>
+#include <gtk/gtkscrolledwindow.h>
+#include <gtk/gtksizegroup.h>
+#include <glade/glade.h>
+
+#include <libmissioncontrol/mc-account.h>
+
+#include <libempathy/empathy-utils.h>
+#include <libempathy/empathy-debug.h>
+#include <libempathy/empathy-conf.h>
+
+#include "empathy-chat-view.h"
+#include "empathy-chat.h"
+#include "empathy-preferences.h"
+#include "empathy-theme-manager.h"
+#include "empathy-ui-utils.h"
+
+#define DEBUG_DOMAIN "ChatView"
+
+/* Number of seconds between timestamps when using normal mode, 5 minutes. */
+#define TIMESTAMP_INTERVAL 300
+
+#define MAX_LINES 800
+#define MAX_SCROLL_TIME 0.4 /* seconds */
+#define SCROLL_DELAY 33     /* milliseconds */
+
+#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_CHAT_VIEW, EmpathyChatViewPriv))
+
+typedef enum {
+       BLOCK_TYPE_NONE,
+       BLOCK_TYPE_SELF,
+       BLOCK_TYPE_OTHER,
+       BLOCK_TYPE_EVENT,
+       BLOCK_TYPE_TIME,
+       BLOCK_TYPE_INVITE
+} BlockType;
+
+struct _EmpathyChatViewPriv {
+       GtkTextBuffer *buffer;
+
+       gboolean       irc_style;
+       time_t         last_timestamp;
+       BlockType      last_block_type;
+
+       gboolean       allow_scrolling;
+       guint          scroll_timeout;
+       GTimer        *scroll_time;
+       gboolean       is_group_chat;
+
+       GtkTextMark   *find_mark_previous;
+       GtkTextMark   *find_mark_next;
+       gboolean       find_wrapped;
+       gboolean       find_last_direction;
+
+       /* This is for the group chat so we know if the "other" last contact
+        * changed, so we know whether to insert a header or not.
+        */
+       EmpathyContact *last_contact;
+
+       guint          notify_system_fonts_id;
+       guint          notify_show_avatars_id;
+};
+
+typedef struct {
+       EmpathySmiley  smiley;
+       const gchar  *pattern;
+} EmpathySmileyPattern;
+
+static const EmpathySmileyPattern smileys[] = {
+       /* Forward smileys. */
+       { EMPATHY_SMILEY_NORMAL,       ":)"  },
+       { EMPATHY_SMILEY_WINK,         ";)"  },
+       { EMPATHY_SMILEY_WINK,         ";-)" },
+       { EMPATHY_SMILEY_BIGEYE,       "=)"  },
+       { EMPATHY_SMILEY_NOSE,         ":-)" },
+       { EMPATHY_SMILEY_CRY,          ":'(" },
+       { EMPATHY_SMILEY_SAD,          ":("  },
+       { EMPATHY_SMILEY_SAD,          ":-(" },
+       { EMPATHY_SMILEY_SCEPTICAL,    ":/"  },
+       { EMPATHY_SMILEY_SCEPTICAL,    ":\\" },
+       { EMPATHY_SMILEY_BIGSMILE,     ":D"  },
+       { EMPATHY_SMILEY_BIGSMILE,     ":-D" },
+       { EMPATHY_SMILEY_INDIFFERENT,  ":|"  },
+       { EMPATHY_SMILEY_TOUNGE,       ":p"  },
+       { EMPATHY_SMILEY_TOUNGE,       ":-p" },
+       { EMPATHY_SMILEY_TOUNGE,       ":P"  },
+       { EMPATHY_SMILEY_TOUNGE,       ":-P" },
+       { EMPATHY_SMILEY_TOUNGE,       ";p"  },
+       { EMPATHY_SMILEY_TOUNGE,       ";-p" },
+       { EMPATHY_SMILEY_TOUNGE,       ";P"  },
+       { EMPATHY_SMILEY_TOUNGE,       ";-P" },
+       { EMPATHY_SMILEY_SHOCKED,      ":o"  },
+       { EMPATHY_SMILEY_SHOCKED,      ":-o" },
+       { EMPATHY_SMILEY_SHOCKED,      ":O"  },
+       { EMPATHY_SMILEY_SHOCKED,      ":-O" },
+       { EMPATHY_SMILEY_COOL,         "8)"  },
+       { EMPATHY_SMILEY_COOL,         "B)"  },
+       { EMPATHY_SMILEY_SORRY,        "*|"  },
+       { EMPATHY_SMILEY_KISS,         ":*"  },
+       { EMPATHY_SMILEY_SHUTUP,       ":#"  },
+       { EMPATHY_SMILEY_SHUTUP,       ":-#" },
+       { EMPATHY_SMILEY_YAWN,         "|O"  },
+       { EMPATHY_SMILEY_CONFUSED,     ":S"  },
+       { EMPATHY_SMILEY_CONFUSED,     ":s"  },
+       { EMPATHY_SMILEY_ANGEL,        "<)"  },
+       { EMPATHY_SMILEY_OOOH,         ":x"  },
+       { EMPATHY_SMILEY_LOOKAWAY,     "*)"  },
+       { EMPATHY_SMILEY_LOOKAWAY,     "*-)" },
+       { EMPATHY_SMILEY_BLUSH,        "*S"  },
+       { EMPATHY_SMILEY_BLUSH,        "*s"  },
+       { EMPATHY_SMILEY_BLUSH,        "*$"  },
+       { EMPATHY_SMILEY_COOLBIGSMILE, "8D"  },
+       { EMPATHY_SMILEY_ANGRY,        ":@"  },
+       { EMPATHY_SMILEY_BOSS,         "@)"  },
+       { EMPATHY_SMILEY_MONKEY,       "#)"  },
+       { EMPATHY_SMILEY_SILLY,        "O)"  },
+       { EMPATHY_SMILEY_SICK,         "+o(" },
+
+       /* Backward smileys. */
+       { EMPATHY_SMILEY_NORMAL,       "(:"  },
+       { EMPATHY_SMILEY_WINK,         "(;"  },
+       { EMPATHY_SMILEY_WINK,         "(-;" },
+       { EMPATHY_SMILEY_BIGEYE,       "(="  },
+       { EMPATHY_SMILEY_NOSE,         "(-:" },
+       { EMPATHY_SMILEY_CRY,          ")':" },
+       { EMPATHY_SMILEY_SAD,          "):"  },
+       { EMPATHY_SMILEY_SAD,          ")-:" },
+       { EMPATHY_SMILEY_SCEPTICAL,    "/:"  },
+       { EMPATHY_SMILEY_SCEPTICAL,    "//:" },
+       { EMPATHY_SMILEY_INDIFFERENT,  "|:"  },
+       { EMPATHY_SMILEY_TOUNGE,       "d:"  },
+       { EMPATHY_SMILEY_TOUNGE,       "d-:" },
+       { EMPATHY_SMILEY_TOUNGE,       "d;"  },
+       { EMPATHY_SMILEY_TOUNGE,       "d-;" },
+       { EMPATHY_SMILEY_SHOCKED,      "o:"  },
+       { EMPATHY_SMILEY_SHOCKED,      "O:"  },
+       { EMPATHY_SMILEY_COOL,         "(8"  },
+       { EMPATHY_SMILEY_COOL,         "(B"  },
+       { EMPATHY_SMILEY_SORRY,        "|*"  },
+       { EMPATHY_SMILEY_KISS,         "*:"  },
+       { EMPATHY_SMILEY_SHUTUP,       "#:"  },
+       { EMPATHY_SMILEY_SHUTUP,       "#-:" },
+       { EMPATHY_SMILEY_YAWN,         "O|"  },
+       { EMPATHY_SMILEY_CONFUSED,     "S:"  },
+       { EMPATHY_SMILEY_CONFUSED,     "s:"  },
+       { EMPATHY_SMILEY_ANGEL,        "(>"  },
+       { EMPATHY_SMILEY_OOOH,         "x:"  },
+       { EMPATHY_SMILEY_LOOKAWAY,     "(*"  },
+       { EMPATHY_SMILEY_LOOKAWAY,     "(-*" },
+       { EMPATHY_SMILEY_BLUSH,        "S*"  },
+       { EMPATHY_SMILEY_BLUSH,        "s*"  },
+       { EMPATHY_SMILEY_BLUSH,        "$*"  },
+       { EMPATHY_SMILEY_ANGRY,        "@:"  },
+       { EMPATHY_SMILEY_BOSS,         "(@"  },
+       { EMPATHY_SMILEY_MONKEY,       "#)"  },
+       { EMPATHY_SMILEY_SILLY,        "(O"  },
+       { EMPATHY_SMILEY_SICK,         ")o+" }
+};
+
+static void     empathy_chat_view_class_init          (EmpathyChatViewClass      *klass);
+static void     empathy_chat_view_init                (EmpathyChatView           *view);
+static void     chat_view_finalize                   (GObject                  *object);
+static gboolean chat_view_drag_motion                (GtkWidget                *widget,
+                                                     GdkDragContext           *context,
+                                                     gint                      x,
+                                                     gint                      y,
+                                                     guint                     time);
+static void     chat_view_size_allocate              (GtkWidget                *widget,
+                                                     GtkAllocation            *alloc);
+static void     chat_view_setup_tags                 (EmpathyChatView           *view);
+static void     chat_view_system_font_update         (EmpathyChatView           *view);
+static void     chat_view_notify_system_font_cb      (EmpathyConf               *conf,
+                                                     const gchar              *key,
+                                                     gpointer                  user_data);
+static void     chat_view_notify_show_avatars_cb     (EmpathyConf               *conf,
+                                                     const gchar              *key,
+                                                     gpointer                  user_data);
+static void     chat_view_populate_popup             (EmpathyChatView           *view,
+                                                     GtkMenu                  *menu,
+                                                     gpointer                  user_data);
+static gboolean chat_view_event_cb                   (EmpathyChatView           *view,
+                                                     GdkEventMotion           *event,
+                                                     GtkTextTag               *tag);
+static gboolean chat_view_url_event_cb               (GtkTextTag               *tag,
+                                                     GObject                  *object,
+                                                     GdkEvent                 *event,
+                                                     GtkTextIter              *iter,
+                                                     GtkTextBuffer            *buffer);
+static void     chat_view_open_address_cb            (GtkMenuItem              *menuitem,
+                                                     const gchar              *url);
+static void     chat_view_copy_address_cb            (GtkMenuItem              *menuitem,
+                                                     const gchar              *url);
+static void     chat_view_clear_view_cb              (GtkMenuItem              *menuitem,
+                                                     EmpathyChatView           *view);
+static void     chat_view_insert_text_with_emoticons (GtkTextBuffer            *buf,
+                                                     GtkTextIter              *iter,
+                                                     const gchar              *str);
+static gboolean chat_view_is_scrolled_down           (EmpathyChatView           *view);
+static void     chat_view_theme_changed_cb           (EmpathyThemeManager       *manager,
+                                                     EmpathyChatView           *view);
+static void     chat_view_maybe_append_date_and_time (EmpathyChatView           *view,
+                                                     EmpathyMessage            *msg);
+static void     chat_view_append_spacing             (EmpathyChatView           *view);
+static void     chat_view_append_text                (EmpathyChatView           *view,
+                                                     const gchar              *body,
+                                                     const gchar              *tag);
+static void     chat_view_maybe_append_fancy_header  (EmpathyChatView           *view,
+                                                     EmpathyMessage            *msg);
+static void     chat_view_append_irc_action          (EmpathyChatView           *view,
+                                                     EmpathyMessage            *msg);
+static void     chat_view_append_fancy_action        (EmpathyChatView           *view,
+                                                     EmpathyMessage            *msg);
+static void     chat_view_append_irc_message         (EmpathyChatView           *view,
+                                                     EmpathyMessage            *msg);
+static void     chat_view_append_fancy_message       (EmpathyChatView           *view,
+                                                     EmpathyMessage            *msg);
+static GdkPixbuf *chat_view_pad_to_size              (GdkPixbuf                *pixbuf,
+                                                     gint                      width,
+                                                     gint                      height,
+                                                     gint                      extra_padding_right);
+
+G_DEFINE_TYPE (EmpathyChatView, empathy_chat_view, GTK_TYPE_TEXT_VIEW);
+
+static void
+empathy_chat_view_class_init (EmpathyChatViewClass *klass)
+{
+       GObjectClass   *object_class = G_OBJECT_CLASS (klass);
+       GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+       object_class->finalize = chat_view_finalize;
+       widget_class->size_allocate = chat_view_size_allocate;
+       widget_class->drag_motion = chat_view_drag_motion; 
+
+       g_type_class_add_private (object_class, sizeof (EmpathyChatViewPriv));
+}
+
+static void
+empathy_chat_view_init (EmpathyChatView *view)
+{
+       EmpathyChatViewPriv *priv;
+       gboolean            show_avatars;
+
+       priv = GET_PRIV (view);
+
+       priv->buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+
+       priv->last_block_type = BLOCK_TYPE_NONE;
+       priv->last_timestamp = 0;
+
+       priv->allow_scrolling = TRUE;
+
+       priv->is_group_chat = FALSE;
+
+       g_object_set (view,
+                     "wrap-mode", GTK_WRAP_WORD_CHAR,
+                     "editable", FALSE,
+                     "cursor-visible", FALSE,
+                     NULL);
+
+       priv->notify_system_fonts_id =
+               empathy_conf_notify_add (empathy_conf_get (),
+                                        "/desktop/gnome/interface/document_font_name",
+                                        chat_view_notify_system_font_cb,
+                                        view);
+       chat_view_system_font_update (view);
+
+       priv->notify_show_avatars_id =
+               empathy_conf_notify_add (empathy_conf_get (),
+                                        EMPATHY_PREFS_UI_SHOW_AVATARS,
+                                        chat_view_notify_show_avatars_cb,
+                                        view);
+
+       chat_view_setup_tags (view);
+
+       empathy_theme_manager_apply_saved (empathy_theme_manager_get (), view);
+
+       show_avatars = FALSE;
+       empathy_conf_get_bool (empathy_conf_get (),
+                              EMPATHY_PREFS_UI_SHOW_AVATARS,
+                              &show_avatars);
+
+       empathy_theme_manager_update_show_avatars (empathy_theme_manager_get (),
+                                                 view, show_avatars);
+
+       g_signal_connect (view,
+                         "populate-popup",
+                         G_CALLBACK (chat_view_populate_popup),
+                         NULL);
+
+       g_signal_connect_object (empathy_theme_manager_get (),
+                                "theme-changed",
+                                G_CALLBACK (chat_view_theme_changed_cb),
+                                view,
+                                0);
+}
+
+static void
+chat_view_finalize (GObject *object)
+{
+       EmpathyChatView     *view;
+       EmpathyChatViewPriv *priv;
+
+       view = EMPATHY_CHAT_VIEW (object);
+       priv = GET_PRIV (view);
+
+       empathy_debug (DEBUG_DOMAIN, "finalize: %p", object);
+
+       empathy_conf_notify_remove (empathy_conf_get (), priv->notify_system_fonts_id);
+       empathy_conf_notify_remove (empathy_conf_get (), priv->notify_show_avatars_id);
+
+       if (priv->last_contact) {
+               g_object_unref (priv->last_contact);
+       }
+       if (priv->scroll_time) {
+               g_timer_destroy (priv->scroll_time);
+       }
+       if (priv->scroll_timeout) {
+               g_source_remove (priv->scroll_timeout);
+       }
+
+       G_OBJECT_CLASS (empathy_chat_view_parent_class)->finalize (object);
+}
+
+static gboolean
+chat_view_drag_motion (GtkWidget        *widget,
+                      GdkDragContext   *context,
+                      gint              x,
+                      gint              y,
+                      guint             time)
+{
+       /* Don't handle drag motion, since we don't want the view to scroll as
+        * the result of dragging something across it.
+        */
+
+       return FALSE;
+}
+
+static void
+chat_view_size_allocate (GtkWidget     *widget,
+                        GtkAllocation *alloc)
+{
+       gboolean down;
+
+       down = chat_view_is_scrolled_down (EMPATHY_CHAT_VIEW (widget));
+
+       GTK_WIDGET_CLASS (empathy_chat_view_parent_class)->size_allocate (widget, alloc);
+
+       if (down) {
+               GtkAdjustment *adj;
+
+               adj = GTK_TEXT_VIEW (widget)->vadjustment;
+               gtk_adjustment_set_value (adj, adj->upper - adj->page_size);
+       }
+}
+
+static void
+chat_view_setup_tags (EmpathyChatView *view)
+{
+       EmpathyChatViewPriv *priv;
+       GtkTextTag         *tag;
+
+       priv = GET_PRIV (view);
+
+       gtk_text_buffer_create_tag (priv->buffer,
+                                   "cut",
+                                   NULL);
+
+       /* FIXME: Move to the theme and come up with something that looks a bit
+        * nicer.
+        */
+       gtk_text_buffer_create_tag (priv->buffer,
+                                   "highlight",
+                                   "background", "yellow",
+                                   NULL);
+
+       tag = gtk_text_buffer_create_tag (priv->buffer,
+                                         "link",
+                                         NULL);
+
+       g_signal_connect (tag,
+                         "event",
+                         G_CALLBACK (chat_view_url_event_cb),
+                         priv->buffer);
+
+       g_signal_connect (view,
+                         "motion-notify-event",
+                         G_CALLBACK (chat_view_event_cb),
+                         tag);
+}
+
+static void
+chat_view_system_font_update (EmpathyChatView *view)
+{
+       PangoFontDescription *font_description = NULL;
+       gchar                *font_name;
+
+       if (empathy_conf_get_string (empathy_conf_get (),
+                                    "/desktop/gnome/interface/document_font_name",
+                                    &font_name) && font_name) {
+               font_description = pango_font_description_from_string (font_name);
+               g_free (font_name);
+       } else {
+               font_description = NULL;
+       }
+
+       gtk_widget_modify_font (GTK_WIDGET (view), font_description);
+
+       if (font_description) {
+               pango_font_description_free (font_description);
+       }
+}
+
+static void
+chat_view_notify_system_font_cb (EmpathyConf  *conf,
+                                const gchar *key,
+                                gpointer     user_data)
+{
+       EmpathyChatView *view;
+       gboolean        show_avatars = FALSE;
+
+       view = user_data;
+
+       chat_view_system_font_update (view);
+
+       /* Ugly, again, to adjust the vertical position of the nick... Will fix
+        * this when reworking the theme manager so that view register
+        * themselves with it instead of the other way around.
+        */
+       empathy_conf_get_bool (conf,
+                              EMPATHY_PREFS_UI_SHOW_AVATARS,
+                              &show_avatars);
+
+       empathy_theme_manager_update_show_avatars (empathy_theme_manager_get (),
+                                                 view, show_avatars);
+}
+
+static void
+chat_view_notify_show_avatars_cb (EmpathyConf  *conf,
+                                 const gchar *key,
+                                 gpointer     user_data)
+{
+       EmpathyChatView     *view;
+       EmpathyChatViewPriv *priv;
+       gboolean            show_avatars = FALSE;
+
+       view = user_data;
+       priv = GET_PRIV (view);
+
+       empathy_conf_get_bool (conf, key, &show_avatars);
+
+       empathy_theme_manager_update_show_avatars (empathy_theme_manager_get (),
+                                                 view, show_avatars);
+}
+
+static void
+chat_view_populate_popup (EmpathyChatView *view,
+                         GtkMenu        *menu,
+                         gpointer        user_data)
+{
+       EmpathyChatViewPriv *priv;
+       GtkTextTagTable    *table;
+       GtkTextTag         *tag;
+       gint                x, y;
+       GtkTextIter         iter, start, end;
+       GtkWidget          *item;
+       gchar              *str = NULL;
+
+       priv = GET_PRIV (view);
+
+       /* Clear menu item */
+       if (gtk_text_buffer_get_char_count (priv->buffer) > 0) {
+               item = gtk_menu_item_new ();
+               gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
+               gtk_widget_show (item);
+
+               item = gtk_image_menu_item_new_from_stock (GTK_STOCK_CLEAR, NULL);
+               gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
+               gtk_widget_show (item);
+
+               g_signal_connect (item,
+                                 "activate",
+                                 G_CALLBACK (chat_view_clear_view_cb),
+                                 view);
+       }
+
+       /* Link context menu items */
+       table = gtk_text_buffer_get_tag_table (priv->buffer);
+       tag = gtk_text_tag_table_lookup (table, "link");
+
+       gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y);
+
+       gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (view),
+                                              GTK_TEXT_WINDOW_WIDGET,
+                                              x, y,
+                                              &x, &y);
+
+       gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (view), &iter, x, y);
+
+       start = end = iter;
+
+       if (gtk_text_iter_backward_to_tag_toggle (&start, tag) &&
+           gtk_text_iter_forward_to_tag_toggle (&end, tag)) {
+               str = gtk_text_buffer_get_text (priv->buffer,
+                                               &start, &end, FALSE);
+       }
+
+       if (G_STR_EMPTY (str)) {
+               g_free (str);
+               return;
+       }
+
+       /* NOTE: Set data just to get the string freed when not needed. */
+       g_object_set_data_full (G_OBJECT (menu),
+                               "url", str,
+                               (GDestroyNotify) g_free);
+
+       item = gtk_menu_item_new ();
+       gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
+       gtk_widget_show (item);
+
+       item = gtk_menu_item_new_with_mnemonic (_("_Copy Link Address"));
+       g_signal_connect (item,
+                         "activate",
+                         G_CALLBACK (chat_view_copy_address_cb),
+                         str);
+       gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
+       gtk_widget_show (item);
+
+       item = gtk_menu_item_new_with_mnemonic (_("_Open Link"));
+       g_signal_connect (item,
+                         "activate",
+                         G_CALLBACK (chat_view_open_address_cb),
+                         str);
+       gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
+       gtk_widget_show (item);
+}
+
+static gboolean
+chat_view_event_cb (EmpathyChatView *view,
+                   GdkEventMotion *event,
+                   GtkTextTag     *tag)
+{
+       static GdkCursor  *hand = NULL;
+       static GdkCursor  *beam = NULL;
+       GtkTextWindowType  type;
+       GtkTextIter        iter;
+       GdkWindow         *win;
+       gint               x, y, buf_x, buf_y;
+
+       type = gtk_text_view_get_window_type (GTK_TEXT_VIEW (view),
+                                             event->window);
+
+       if (type != GTK_TEXT_WINDOW_TEXT) {
+               return FALSE;
+       }
+
+       /* Get where the pointer really is. */
+       win = gtk_text_view_get_window (GTK_TEXT_VIEW (view), type);
+       if (!win) {
+               return FALSE;
+       }
+
+       gdk_window_get_pointer (win, &x, &y, NULL);
+
+       /* Get the iter where the cursor is at */
+       gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (view), type,
+                                              x, y,
+                                              &buf_x, &buf_y);
+
+       gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (view),
+                                           &iter,
+                                           buf_x, buf_y);
+
+       if (gtk_text_iter_has_tag (&iter, tag)) {
+               if (!hand) {
+                       hand = gdk_cursor_new (GDK_HAND2);
+                       beam = gdk_cursor_new (GDK_XTERM);
+               }
+               gdk_window_set_cursor (win, hand);
+       } else {
+               if (!beam) {
+                       beam = gdk_cursor_new (GDK_XTERM);
+               }
+               gdk_window_set_cursor (win, beam);
+       }
+
+       return FALSE;
+}
+
+static gboolean
+chat_view_url_event_cb (GtkTextTag    *tag,
+                       GObject       *object,
+                       GdkEvent      *event,
+                       GtkTextIter   *iter,
+                       GtkTextBuffer *buffer)
+{
+       GtkTextIter  start, end;
+       gchar       *str;
+
+       /* If the link is being selected, don't do anything. */
+       gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
+       if (gtk_text_iter_get_offset (&start) != gtk_text_iter_get_offset (&end)) {
+               return FALSE;
+       }
+
+       if (event->type == GDK_BUTTON_RELEASE && event->button.button == 1) {
+               start = end = *iter;
+
+               if (gtk_text_iter_backward_to_tag_toggle (&start, tag) &&
+                   gtk_text_iter_forward_to_tag_toggle (&end, tag)) {
+                       str = gtk_text_buffer_get_text (buffer,
+                                                       &start,
+                                                       &end,
+                                                       FALSE);
+
+                       empathy_url_show (str);
+                       g_free (str);
+               }
+       }
+
+       return FALSE;
+}
+
+static void
+chat_view_open_address_cb (GtkMenuItem *menuitem, const gchar *url)
+{
+       empathy_url_show (url);
+}
+
+static void
+chat_view_copy_address_cb (GtkMenuItem *menuitem, const gchar *url)
+{
+       GtkClipboard *clipboard;
+
+       clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+       gtk_clipboard_set_text (clipboard, url, -1);
+
+       clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
+       gtk_clipboard_set_text (clipboard, url, -1);
+}
+
+static void
+chat_view_clear_view_cb (GtkMenuItem *menuitem, EmpathyChatView *view)
+{
+       empathy_chat_view_clear (view);
+}
+
+static void
+chat_view_insert_text_with_emoticons (GtkTextBuffer *buf,
+                                     GtkTextIter   *iter,
+                                     const gchar   *str)
+{
+       const gchar *p;
+       gunichar     c, prev_c;
+       gint         i;
+       gint         match;
+       gint         submatch;
+       gboolean     use_smileys = FALSE;
+
+       empathy_conf_get_bool (empathy_conf_get (),
+                              EMPATHY_PREFS_CHAT_SHOW_SMILEYS,
+                              &use_smileys);
+
+       if (!use_smileys) {
+               gtk_text_buffer_insert (buf, iter, str, -1);
+               return;
+       }
+
+       while (*str) {
+               gint         smileys_index[G_N_ELEMENTS (smileys)];
+               GdkPixbuf   *pixbuf;
+               gint         len;
+               const gchar *start;
+
+               memset (smileys_index, 0, sizeof (smileys_index));
+
+               match = -1;
+               submatch = -1;
+               p = str;
+               prev_c = 0;
+
+               while (*p) {
+                       c = g_utf8_get_char (p);
+
+                       if (match != -1 && g_unichar_isspace (c)) {
+                               break;
+                       } else {
+                               match = -1;
+                       }
+
+                       if (submatch != -1 || prev_c == 0 || g_unichar_isspace (prev_c)) {
+                               submatch = -1;
+
+                               for (i = 0; i < G_N_ELEMENTS (smileys); i++) {
+                                       /* Only try to match if we already have
+                                        * a beginning match for the pattern, or
+                                        * if it's the first character in the
+                                        * pattern, if it's not in the middle of
+                                        * a word.
+                                        */
+                                       if (((smileys_index[i] == 0 && (prev_c == 0 || g_unichar_isspace (prev_c))) ||
+                                            smileys_index[i] > 0) &&
+                                           smileys[i].pattern[smileys_index[i]] == c) {
+                                               submatch = i;
+
+                                               smileys_index[i]++;
+                                               if (!smileys[i].pattern[smileys_index[i]]) {
+                                                       match = i;
+                                               }
+                                       } else {
+                                               smileys_index[i] = 0;
+                                       }
+                               }
+                       }
+
+                       prev_c = c;
+                       p = g_utf8_next_char (p);
+               }
+
+               if (match == -1) {
+                       gtk_text_buffer_insert (buf, iter, str, -1);
+                       return;
+               }
+
+               start = p - strlen (smileys[match].pattern);
+
+               if (start > str) {
+                       len = start - str;
+                       gtk_text_buffer_insert (buf, iter, str, len);
+               }
+
+               pixbuf = empathy_chat_view_get_smiley_image (smileys[match].smiley);
+               gtk_text_buffer_insert_pixbuf (buf, iter, pixbuf);
+
+               gtk_text_buffer_insert (buf, iter, " ", 1);
+
+               str = g_utf8_find_next_char (p, NULL);
+       }
+}
+
+static gboolean
+chat_view_is_scrolled_down (EmpathyChatView *view)
+{
+       GtkWidget *sw;
+
+       sw = gtk_widget_get_parent (GTK_WIDGET (view));
+       if (GTK_IS_SCROLLED_WINDOW (sw)) {
+               GtkAdjustment *vadj;
+
+               vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (sw));
+
+               if (vadj->value + vadj->page_size / 2 < vadj->upper - vadj->page_size) {
+                       return FALSE;
+               }
+       }
+
+       return TRUE;
+}
+
+static void
+chat_view_maybe_trim_buffer (EmpathyChatView *view)
+{
+       EmpathyChatViewPriv *priv;
+       GtkTextIter         top, bottom;
+       gint                line;
+       gint                remove;
+       GtkTextTagTable    *table;
+       GtkTextTag         *tag;
+
+       priv = GET_PRIV (view);
+
+       gtk_text_buffer_get_end_iter (priv->buffer, &bottom);
+       line = gtk_text_iter_get_line (&bottom);
+       if (line < MAX_LINES) {
+               return;
+       }
+
+       remove = line - MAX_LINES;
+       gtk_text_buffer_get_start_iter (priv->buffer, &top);
+
+       bottom = top;
+       if (!gtk_text_iter_forward_lines (&bottom, remove)) {
+               return;
+       }
+
+       /* Track backwords to a place where we can safely cut, we don't do it in
+        * the middle of a tag.
+        */
+       table = gtk_text_buffer_get_tag_table (priv->buffer);
+       tag = gtk_text_tag_table_lookup (table, "cut");
+       if (!tag) {
+               return;
+       }
+
+       if (!gtk_text_iter_forward_to_tag_toggle (&bottom, tag)) {
+               return;
+       }
+
+       if (!gtk_text_iter_equal (&top, &bottom)) {
+               gtk_text_buffer_delete (priv->buffer, &top, &bottom);
+       }
+}
+
+static void
+chat_view_maybe_append_date_and_time (EmpathyChatView *view,
+                                     EmpathyMessage  *msg)
+{
+       EmpathyChatViewPriv *priv;
+       const gchar        *tag;
+       time_t              timestamp;
+       GDate              *date, *last_date;
+       GtkTextIter         iter;
+       gboolean            append_date, append_time;
+       GString            *str;
+
+       priv = GET_PRIV (view);
+
+       if (priv->irc_style) {
+               tag = "irc-time";
+       } else {
+               tag = "fancy-time";
+       }
+
+       if (priv->last_block_type == BLOCK_TYPE_TIME) {
+               return;
+       }
+
+       str = g_string_new (NULL);
+
+       timestamp = 0;
+       if (msg) {
+               timestamp = empathy_message_get_timestamp (msg);
+       }
+
+       if (timestamp <= 0) {
+               timestamp = empathy_time_get_current ();
+       }
+
+       date = g_date_new ();
+       g_date_set_time (date, timestamp);
+
+       last_date = g_date_new ();
+       g_date_set_time (last_date, priv->last_timesta