diff options
Diffstat (limited to 'libempathy-gtk')
36 files changed, 1704 insertions, 1194 deletions
diff --git a/libempathy-gtk/Makefile.am b/libempathy-gtk/Makefile.am index 6f3b99ba6..2065589e3 100644 --- a/libempathy-gtk/Makefile.am +++ b/libempathy-gtk/Makefile.am @@ -49,7 +49,7 @@ libempathy_gtk_la_SOURCES = \ empathy-profile-chooser.c \ empathy-smiley-manager.c \ empathy-spell.c \ - empathy-spell-dialog.c \ + empathy-status-preset-dialog.c \ empathy-theme-boxes.c \ empathy-theme-irc.c \ empathy-theme-manager.c \ @@ -102,7 +102,7 @@ libempathy_gtk_headers = \ empathy-profile-chooser.h \ empathy-smiley-manager.h \ empathy-spell.h \ - empathy-spell-dialog.h \ + empathy-status-preset-dialog.h \ empathy-theme-boxes.h \ empathy-theme-irc.h \ empathy-theme-manager.h \ @@ -117,7 +117,6 @@ uidir = $(datadir)/empathy ui_DATA = \ empathy-contact-widget.ui \ empathy-contact-dialogs.ui \ - empathy-presence-chooser.ui \ empathy-account-widget-generic.ui \ empathy-account-widget-jabber.ui \ empathy-account-widget-msn.ui \ @@ -128,7 +127,7 @@ ui_DATA = \ empathy-account-widget-yahoo.ui \ empathy-account-widget-groupwise.ui \ empathy-account-widget-aim.ui \ - empathy-spell-dialog.ui \ + empathy-status-preset-dialog.ui \ empathy-log-window.ui \ empathy-chat.ui \ empathy-new-message-dialog.ui diff --git a/libempathy-gtk/empathy-account-chooser.c b/libempathy-gtk/empathy-account-chooser.c index 8c402c07a..5d11e8e1e 100644 --- a/libempathy-gtk/empathy-account-chooser.c +++ b/libempathy-gtk/empathy-account-chooser.c @@ -37,6 +37,23 @@ #include "empathy-ui-utils.h" #include "empathy-account-chooser.h" +/** + * SECTION:empathy-account-chooser + * @title:EmpathyAccountChooser + * @short_description: A widget used to choose from a list of accounts + * @include: libempathy-gtk/empathy-account-chooser.h + * + * #EmpathyAccountChooser is a widget which extends #GtkComboBox to provide + * a chooser of available accounts. + */ + +/** + * EmpathyAccountChooser: + * @parent: parent object + * + * Widget which extends #GtkComboBox to provide a chooser of available accounts. + */ + #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAccountChooser) typedef struct { EmpathyAccountManager *manager; @@ -112,6 +129,11 @@ empathy_account_chooser_class_init (EmpathyAccountChooserClass *klass) object_class->get_property = account_chooser_get_property; object_class->set_property = account_chooser_set_property; + /** + * EmpathyAccountChooser:has-all-option: + * + * Have an additional option in the list to mean all accounts. + */ g_object_class_install_property (object_class, PROP_HAS_ALL_OPTION, g_param_spec_boolean ("has-all-option", @@ -209,6 +231,13 @@ account_chooser_set_property (GObject *object, }; } +/** + * empathy_account_chooser_new: + * + * Creates a new #EmpathyAccountChooser. + * + * Return value: A new #EmpathyAccountChooser + */ GtkWidget * empathy_account_chooser_new (void) { @@ -219,8 +248,18 @@ empathy_account_chooser_new (void) return chooser; } +/** + * empathy_account_chooser_dup_account: + * @chooser: an #EmpathyAccountChooser + * + * Returns the account which is currently selected in the chooser or %NULL + * if there is no account selected. The #McAccount returned should be + * unrefed with g_object_unref() when finished with. + * + * Return value: a new ref to the #McAccount currently selected, or %NULL. + */ McAccount * -empathy_account_chooser_get_account (EmpathyAccountChooser *chooser) +empathy_account_chooser_dup_account (EmpathyAccountChooser *chooser) { EmpathyAccountChooserPriv *priv; McAccount *account; @@ -241,6 +280,44 @@ empathy_account_chooser_get_account (EmpathyAccountChooser *chooser) return account; } +/** + * empathy_account_chooser_get_connection: + * @chooser: an #EmpathyAccountChooser + * + * Returns a borrowed reference to the #TpConnection associated with the + * account currently selected. The caller must reference the returned object with + * g_object_ref() if it will be kept + * + * Return value: a borrowed reference to the #TpConnection associated with the + * account curently selected. + */ +TpConnection * +empathy_account_chooser_get_connection (EmpathyAccountChooser *chooser) +{ + EmpathyAccountChooserPriv *priv; + McAccount *account; + TpConnection *connection; + + g_return_val_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser), NULL); + + priv = GET_PRIV (chooser); + + account = empathy_account_chooser_dup_account (chooser); + connection = empathy_account_manager_get_connection (priv->manager, account); + g_object_unref (account); + + return connection; +} + +/** + * empathy_account_chooser_set_account: + * @chooser: an #EmpathyAccountChooser + * @account: an #McAccount + * + * Sets the currently selected account to @account, if it exists in the list. + * + * Return value: whether the chooser was set to @account. + */ gboolean empathy_account_chooser_set_account (EmpathyAccountChooser *chooser, McAccount *account) @@ -266,6 +343,16 @@ empathy_account_chooser_set_account (EmpathyAccountChooser *chooser, return data.set; } +/** + * empathy_account_chooser_get_has_all_option: + * @chooser: an #EmpathyAccountChooser + * + * Returns whether @chooser has the #EmpathyAccountChooser:has-all-option property + * set to true. + * + * Return value: whether @chooser has the #EmpathyAccountChooser:has-all-option property + * enabled. + */ gboolean empathy_account_chooser_get_has_all_option (EmpathyAccountChooser *chooser) { @@ -278,6 +365,13 @@ empathy_account_chooser_get_has_all_option (EmpathyAccountChooser *chooser) return priv->has_all_option; } +/** + * empathy_account_chooser_set_has_all_option: + * @chooser: an #EmpathyAccountChooser + * @has_all_option: a new value for the #EmpathyAccountChooser:has-all-option property + * + * Sets the #EmpathyAccountChooser:has-all-option property. + */ void empathy_account_chooser_set_has_all_option (EmpathyAccountChooser *chooser, gboolean has_all_option) @@ -618,6 +712,15 @@ account_chooser_filter_foreach (GtkTreeModel *model, return FALSE; } +/** + * empathy_account_chooser_set_filter: + * @chooser: an #EmpathyAccountChooser + * @filter: a filter + * @user_data: data to pass to @filter, or %NULL + * + * Sets a filter on the @chooser so only accounts that are %TRUE in the eyes + * of the filter are visible in the @chooser. + */ void empathy_account_chooser_set_filter (EmpathyAccountChooser *chooser, EmpathyAccountChooserFilterFunc filter, @@ -639,6 +742,27 @@ empathy_account_chooser_set_filter (EmpathyAccountChooser *chooser, gtk_tree_model_foreach (model, account_chooser_filter_foreach, chooser); } +/** + * EmpathyAccountChooserFilterFunc: + * @account: an #McAccount + * @user_data: user data, or %NULL + * + * A function which decides whether the account indicated by @account + * is visible. + * + * Return value: whether the account indicated by @account is visible. + */ + +/** + * empathy_account_chooser_filter_is_connected: + * @account: an #McAccount + * @user_data: user data or %NULL + * + * A useful #EmpathyAccountChooserFilterFunc that one could pass into + * empathy_account_chooser_set_filter() and only show connected accounts. + * + * Return value: Whether @account is connected + */ gboolean empathy_account_chooser_filter_is_connected (McAccount *account, gpointer user_data) diff --git a/libempathy-gtk/empathy-account-chooser.h b/libempathy-gtk/empathy-account-chooser.h index c15923bc3..98d568bcc 100644 --- a/libempathy-gtk/empathy-account-chooser.h +++ b/libempathy-gtk/empathy-account-chooser.h @@ -47,6 +47,8 @@ typedef struct _EmpathyAccountChooserClass EmpathyAccountChooserClass; struct _EmpathyAccountChooser { GtkComboBox parent; + + /*<private>*/ gpointer priv; }; @@ -56,7 +58,8 @@ struct _EmpathyAccountChooserClass { GType empathy_account_chooser_get_type (void) G_GNUC_CONST; GtkWidget * empathy_account_chooser_new (void); -McAccount * empathy_account_chooser_get_account (EmpathyAccountChooser *chooser); +McAccount * empathy_account_chooser_dup_account (EmpathyAccountChooser *chooser); +TpConnection * empathy_account_chooser_get_connection (EmpathyAccountChooser *chooser); gboolean empathy_account_chooser_set_account (EmpathyAccountChooser *chooser, McAccount *account); gboolean empathy_account_chooser_get_has_all_option (EmpathyAccountChooser *chooser); diff --git a/libempathy-gtk/empathy-account-widget-irc.c b/libempathy-gtk/empathy-account-widget-irc.c index 3af842415..cc86a5aaa 100644 --- a/libempathy-gtk/empathy-account-widget-irc.c +++ b/libempathy-gtk/empathy-account-widget-irc.c @@ -50,9 +50,6 @@ typedef struct { GtkWidget *vbox_settings; GtkWidget *combobox_network; - GtkWidget *button_add_network; - GtkWidget *button_network; - GtkWidget *button_remove; } EmpathyAccountWidgetIrc; enum { @@ -462,9 +459,6 @@ empathy_account_widget_irc_new (McAccount *account) gui = empathy_builder_get_file (filename, "vbox_irc_settings", &settings->vbox_settings, "combobox_network", &settings->combobox_network, - "button_network", &settings->button_network, - "button_add_network", &settings->button_add_network, - "button_remove", &settings->button_remove, NULL); g_free (filename); @@ -501,7 +495,7 @@ empathy_account_widget_irc_new (McAccount *account) "vbox_irc_settings", "destroy", account_widget_irc_destroy_cb, "button_network", "clicked", account_widget_irc_button_edit_network_clicked_cb, "button_add_network", "clicked", account_widget_irc_button_add_network_clicked_cb, - "button_remove", "clicked", account_widget_irc_button_remove_clicked_cb, + "button_remove_network", "clicked", account_widget_irc_button_remove_clicked_cb, "combobox_network", "changed", account_widget_irc_combobox_network_changed_cb, NULL); diff --git a/libempathy-gtk/empathy-account-widget-irc.ui b/libempathy-gtk/empathy-account-widget-irc.ui index f499866eb..76c67f711 100644 --- a/libempathy-gtk/empathy-account-widget-irc.ui +++ b/libempathy-gtk/empathy-account-widget-irc.ui @@ -3,7 +3,6 @@ <requires lib="gtk+" version="2.16"/> <!-- interface-naming-policy toplevel-contextual --> <object class="GtkDialog" id="irc_network_dialog"> - <property name="visible">True</property> <property name="border_width">5</property> <property name="title" translatable="yes">Network</property> <property name="window_position">center-on-parent</property> @@ -418,7 +417,7 @@ </packing> </child> <child> - <object class="GtkButton" id="button_remove"> + <object class="GtkButton" id="button_remove_network"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> @@ -444,7 +443,7 @@ </packing> </child> <child> - <object class="GtkLabel" id="label_network"> + <object class="GtkLabel" id="label_network2"> <property name="visible">True</property> <property name="xalign">0</property> <property name="label" translatable="yes">Network:</property> diff --git a/libempathy-gtk/empathy-avatar-chooser.c b/libempathy-gtk/empathy-avatar-chooser.c index 02aa689eb..c86b85d25 100644 --- a/libempathy-gtk/empathy-avatar-chooser.c +++ b/libempathy-gtk/empathy-avatar-chooser.c @@ -30,7 +30,7 @@ #include <gio/gio.h> #include <libempathy/empathy-utils.h> -#include <libempathy/empathy-contact-factory.h> +#include <libempathy/empathy-tp-contact-factory.h> #include "empathy-avatar-chooser.h" #include "empathy-conf.h" @@ -39,15 +39,31 @@ #define DEBUG_FLAG EMPATHY_DEBUG_OTHER #include <libempathy/empathy-debug.h> +/** + * SECTION:empathy-avatar-chooser + * @title: EmpathyAvatarChooser + * @short_description: A widget used to change avatar + * @include: libempathy-gtk/empathy-avatar-chooser.h + * + * #EmpathyAvatarChooser is a widget which extends #GtkButton to + * provide a way of changing avatar. + */ + +/** + * EmpathyAvatarChooser: + * @parent: parent object + * + * Widget which extends #GtkButton to provide a way of changing avatar. + */ + #define AVATAR_SIZE_SAVE 96 #define AVATAR_SIZE_VIEW 64 #define DEFAULT_DIR DATADIR"/pixmaps/faces" #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAvatarChooser) typedef struct { - EmpathyContactFactory *contact_factory; - McAccount *account; - EmpathyTpContactFactory *tp_contact_factory; + EmpathyTpContactFactory *factory; + TpConnection *connection; GtkFileChooser *chooser_dialog; gulong ready_handler_id; @@ -56,8 +72,8 @@ typedef struct { } EmpathyAvatarChooserPriv; static void avatar_chooser_finalize (GObject *object); -static void avatar_chooser_set_account (EmpathyAvatarChooser *self, - McAccount *account); +static void avatar_chooser_set_connection (EmpathyAvatarChooser *self, + TpConnection *connection); static void avatar_chooser_set_image (EmpathyAvatarChooser *chooser, EmpathyAvatar *avatar, GdkPixbuf *pixbuf, @@ -96,7 +112,7 @@ enum { enum { PROP_0, - PROP_ACCOUNT + PROP_CONNECTION }; static guint signals [LAST_SIGNAL]; @@ -125,8 +141,8 @@ avatar_chooser_get_property (GObject *object, EmpathyAvatarChooserPriv *priv = GET_PRIV (object); switch (param_id) { - case PROP_ACCOUNT: - g_value_set_object (value, priv->account); + case PROP_CONNECTION: + g_value_set_object (value, priv->connection); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -143,8 +159,8 @@ avatar_chooser_set_property (GObject *object, EmpathyAvatarChooser *self = EMPATHY_AVATAR_CHOOSER (object); switch (param_id) { - case PROP_ACCOUNT: - avatar_chooser_set_account (self, g_value_get_object (value)); + case PROP_CONNECTION: + avatar_chooser_set_connection (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -162,6 +178,13 @@ empathy_avatar_chooser_class_init (EmpathyAvatarChooserClass *klass) object_class->get_property = avatar_chooser_get_property; object_class->set_property = avatar_chooser_set_property; + /** + * EmpathyAvatarChooser::changed: + * @chooser: an #EmpathyAvatarChooser + * + * Emitted when the chosen avatar has changed. + * + */ signals[CHANGED] = g_signal_new ("changed", G_TYPE_FROM_CLASS (klass), @@ -171,15 +194,21 @@ empathy_avatar_chooser_class_init (EmpathyAvatarChooserClass *klass) g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - param_spec = g_param_spec_object ("account", - "McAccount", - "McAccount whose avatar should be " + /** + * EmpathyAvatarChooser:connection: + * + * The #TpConnection whose avatar should be shown and modified by + * the #EmpathyAvatarChooser instance. + */ + param_spec = g_param_spec_object ("connection", + "TpConnection", + "TpConnection whose avatar should be " "shown and modified by this widget", - MC_TYPE_ACCOUNT, + TP_TYPE_CONNECTION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, - PROP_ACCOUNT, + PROP_CONNECTION, param_spec); g_type_class_add_private (object_class, sizeof (EmpathyAvatarChooserPriv)); @@ -214,8 +243,6 @@ empathy_avatar_chooser_init (EmpathyAvatarChooser *chooser) G_CALLBACK (avatar_chooser_clicked_cb), chooser); - priv->contact_factory = empathy_contact_factory_dup_singleton (); - empathy_avatar_chooser_set (chooser, NULL); } @@ -226,11 +253,9 @@ avatar_chooser_finalize (GObject *object) priv = GET_PRIV (object); - avatar_chooser_set_account (EMPATHY_AVATAR_CHOOSER (object), NULL); - g_assert (priv->account == NULL); - g_assert (priv->tp_contact_factory == NULL); - - g_object_unref (priv->contact_factory); + avatar_chooser_set_connection (EMPATHY_AVATAR_CHOOSER (object), NULL); + g_assert (priv->connection == NULL); + g_assert (priv->factory == NULL); if (priv->avatar != NULL) { empathy_avatar_unref (priv->avatar); @@ -240,51 +265,22 @@ avatar_chooser_finalize (GObject *object) } static void -avatar_chooser_tp_cf_ready_cb (EmpathyTpContactFactory *tp_cf, - GParamSpec *unused, - EmpathyAvatarChooser *self) -{ - EmpathyAvatarChooserPriv *priv = GET_PRIV (self); - gboolean ready; - - /* sanity check that we're listening on the right ETpCF */ - g_assert (priv->tp_contact_factory == tp_cf); - - ready = empathy_tp_contact_factory_is_ready (tp_cf); - gtk_widget_set_sensitive (GTK_WIDGET (self), ready); -} - -static void -avatar_chooser_set_account (EmpathyAvatarChooser *self, - McAccount *account) +avatar_chooser_set_connection (EmpathyAvatarChooser *self, + TpConnection *connection) { EmpathyAvatarChooserPriv *priv = GET_PRIV (self); - if (priv->account != NULL) { - g_object_unref (priv->account); - priv->account = NULL; + if (priv->connection != NULL) { + g_object_unref (priv->connection); + priv->connection = NULL; - g_assert (priv->tp_contact_factory != NULL); - - g_signal_handler_disconnect (priv->tp_contact_factory, - priv->ready_handler_id); - priv->ready_handler_id = 0; - - g_object_unref (priv->tp_contact_factory); - priv->tp_contact_factory = NULL; + g_object_unref (priv->factory); + priv->factory = NULL; } - if (account != NULL) { - priv->account = g_object_ref (account); - priv->tp_contact_factory = g_object_ref ( - empathy_contact_factory_get_tp_factory ( - priv->contact_factory, priv->account)); - - priv->ready_handler_id = g_signal_connect ( - priv->tp_contact_factory, "notify::ready", - G_CALLBACK (avatar_chooser_tp_cf_ready_cb), self); - avatar_chooser_tp_cf_ready_cb (priv->tp_contact_factory, NULL, - self); + if (connection != NULL) { + priv->connection = g_object_ref (connection); + priv->factory = empathy_tp_contact_factory_dup_singleton (connection); } } @@ -412,7 +408,6 @@ avatar_chooser_maybe_convert_and_scale (EmpathyAvatarChooser *chooser, EmpathyAvatar *avatar) { EmpathyAvatarChooserPriv *priv = GET_PRIV (chooser); - EmpathyTpContactFactory *tp_cf = priv->tp_contact_factory; guint max_width = 0, max_height = 0, max_size = 0; gchar **mime_types = NULL; gboolean needs_conversion = FALSE; @@ -424,15 +419,7 @@ avatar_chooser_maybe_convert_and_scale (EmpathyAvatarChooser *chooser, gchar *converted_image_data = NULL; gsize converted_image_size = 0; - /* This should only be called if the user is setting a new avatar, - * which should only be allowed once the avatar requirements have been - * discovered. - */ - g_return_val_if_fail (tp_cf != NULL, NULL); - g_return_val_if_fail (empathy_tp_contact_factory_is_ready (tp_cf), - NULL); - - g_object_get (tp_cf, + g_object_get (priv->factory, "avatar-mime-types", &mime_types, /* Needs g_strfreev-ing */ "avatar-max-width", &max_width, "avatar-max-height", &max_height, @@ -901,16 +888,6 @@ avatar_chooser_response_cb (GtkWidget *widget, priv->chooser_dialog = NULL; - if (response == GTK_RESPONSE_CANCEL) { - goto out; - } - - /* Check if we went non-ready since displaying the dialog. */ - if (!empathy_tp_contact_factory_is_ready (priv->tp_contact_factory)) { - DEBUG ("Can't set avatar when contact factory isn't ready."); - goto out; - } - if (response == GTK_RESPONSE_OK) { gchar *filename; gchar *path; @@ -932,7 +909,6 @@ avatar_chooser_response_cb (GtkWidget *widget, avatar_chooser_clear_image (chooser); } -out: gtk_widget_destroy (widget); } @@ -1037,12 +1013,26 @@ avatar_chooser_clicked_cb (GtkWidget *button, g_free (saved_dir); } +/** + * empathy_avatar_chooser_new: + * + * Creates a new #EmpathyAvatarChooser. + * + * Return value: a new #EmpathyAvatarChooser + */ GtkWidget * empathy_avatar_chooser_new () { return g_object_new (EMPATHY_TYPE_AVATAR_CHOOSER, NULL); } +/** + * empathy_avatar_chooser_set: + * @chooser: an #EmpathyAvatarChooser + * @avatar: a new #EmpathyAvatar + * + * Sets the @chooser to display the avatar indicated by @avatar. + */ void empathy_avatar_chooser_set (EmpathyAvatarChooser *chooser, EmpathyAvatar *avatar) @@ -1056,6 +1046,15 @@ empathy_avatar_chooser_set (EmpathyAvatarChooser *chooser, } } +/** + * empathy_avatar_chooser_get_image_data: + * @chooser: an #EmpathyAvatarChooser + * @data: avatar bytes + * @data_size: size of @data + * @mime_type: avatar mime-type + * + * Gets image data about the currently selected avatar. + */ void empathy_avatar_chooser_get_image_data (EmpathyAvatarChooser *chooser, const gchar **data, diff --git a/libempathy-gtk/empathy-avatar-chooser.h b/libempathy-gtk/empathy-avatar-chooser.h index bdc5b40ae..564c1f37d 100644 --- a/libempathy-gtk/empathy-avatar-chooser.h +++ b/libempathy-gtk/empathy-avatar-chooser.h @@ -41,6 +41,8 @@ typedef struct _EmpathyAvatarChooserClass EmpathyAvatarChooserClass; struct _EmpathyAvatarChooser { GtkButton parent; + + /*<private>*/ gpointer priv; }; diff --git a/libempathy-gtk/empathy-avatar-image.c b/libempathy-gtk/empathy-avatar-image.c index 51f30bdd5..e5513231b 100644 --- a/libempathy-gtk/empathy-avatar-image.c +++ b/libempathy-gtk/empathy-avatar-image.c @@ -33,6 +33,22 @@ #include "empathy-avatar-image.h" #include "empathy-ui-utils.h" +/** + * SECTION:empathy-avatar-image + * @title: EmpathyAvatarImage + * @short_description: A widget to display an avatar + * @include: libempathy-gtk/empathy-avatar-image.h + * + * #EmpathyAvatarImage is a widget which displays an avatar. + */ + +/** + * EmpathyAvatarImage: + * @parent: parent object + * + * Widget which displays an avatar. + */ + #define MAX_SMALL 64 #define MAX_LARGE 400 @@ -251,6 +267,13 @@ avatar_image_button_release_event (GtkWidget *widget, GdkEventButton *event) return TRUE; } +/** + * empathy_avatar_image_new: + * + * Creates a new #EmpathyAvatarImage. + * + * Return value: a new #EmpathyAvatarImage + */ GtkWidget * empathy_avatar_image_new (void) { @@ -261,6 +284,13 @@ empathy_avatar_image_new (void) return GTK_WIDGET (avatar_image); } +/** + * empathy_avatar_image_set: + * @avatar_image: an #EmpathyAvatarImage + * @avatar: the #EmpathyAvatar to set @avatar_image to + * + * Sets @avatar_image to display the avatar indicated by @avatar. + */ void empathy_avatar_image_set (EmpathyAvatarImage *avatar_image, EmpathyAvatar *avatar) diff --git a/libempathy-gtk/empathy-avatar-image.h b/libempathy-gtk/empathy-avatar-image.h index d6a6cd0b0..8969c1227 100644 --- a/libempathy-gtk/empathy-avatar-image.h +++ b/libempathy-gtk/empathy-avatar-image.h @@ -42,6 +42,8 @@ typedef struct _EmpathyAvatarImageClass EmpathyAvatarImageClass; struct _EmpathyAvatarImage { GtkEventBox parent; + + /*<private>*/ gpointer priv; }; diff --git a/libempathy-gtk/empathy-chat.c b/libempathy-gtk/empathy-chat.c index 7d9390274..425a1c555 100644 --- a/libempathy-gtk/empathy-chat.c +++ b/libempathy-gtk/empathy-chat.c @@ -45,7 +45,6 @@ #include "empathy-chat.h" #include "empathy-conf.h" #include "empathy-spell.h" -#include "empathy-spell-dialog.h" #include "empathy-contact-list-store.h" #include "empathy-contact-list-view.h" #include "empathy-contact-menu.h" @@ -65,7 +64,6 @@ #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyChat) typedef struct { EmpathyTpChat *tp_chat; - gulong tp_chat_destroy_handler; McAccount *account; gchar *id; gchar *name; @@ -190,17 +188,15 @@ chat_connect_channel_reconnected (EmpathyDispatchOperation *dispatch, } static void -chat_connection_changed_cb (EmpathyAccountManager *manager, - McAccount *account, - TpConnectionStatusReason reason, - TpConnectionStatus current, - TpConnectionStatus previous, - EmpathyChat *chat) +chat_new_connection_cb (EmpathyAccountManager *manager, + TpConnection *connection, + EmpathyChat *chat) { EmpathyChatPriv *priv = GET_PRIV (chat); + McAccount *account; - if (current == TP_CONNECTION_STATUS_CONNECTED && !priv->tp_chat && - empathy_account_equal (account, priv->account) && + account = empathy_account_manager_get_account (manager, connection); + if (!priv->tp_chat && empathy_account_equal (account, priv->account) && priv->handle_type != TP_HANDLE_TYPE_NONE && !EMP_STR_EMPTY (priv->id)) { @@ -208,12 +204,14 @@ chat_connection_changed_cb (EmpathyAccountManager *manager, switch (priv->handle_type) { case TP_HANDLE_TYPE_CONTACT: - empathy_dispatcher_chat_with_contact_id (account, priv->id, + empathy_dispatcher_chat_with_contact_id ( + connection, priv->id, chat_connect_channel_reconnected, chat); break; case TP_HANDLE_TYPE_ROOM: - empathy_dispatcher_join_muc (account, priv->id, + empathy_dispatcher_join_muc (connection, + priv->id, chat_connect_channel_reconnected, chat); break; @@ -596,7 +594,7 @@ chat_property_changed_cb (EmpathyTpChat *tp_chat, static void chat_input_text_buffer_changed_cb (GtkTextBuffer *buffer, - EmpathyChat *chat) + EmpathyChat *chat) { EmpathyChatPriv *priv; GtkTextIter start, end; @@ -612,8 +610,8 @@ chat_input_text_buffer_changed_cb (GtkTextBuffer *buffer, } empathy_conf_get_bool (empathy_conf_get (), - EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED, - &spell_checker); + EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED, + &spell_checker); gtk_text_buffer_get_start_iter (buffer, &start); @@ -932,13 +930,42 @@ chat_spell_free (EmpathyChatSpell *chat_spell) } static void -chat_text_check_word_spelling_cb (GtkMenuItem *menuitem, - EmpathyChatSpell *chat_spell) +chat_spelling_menu_activate_cb (GtkMenuItem *menu_item, + EmpathyChatSpell *chat_spell) { - empathy_spell_dialog_show (chat_spell->chat, - &chat_spell->start, - &chat_spell->end, - chat_spell->word); + empathy_chat_correct_word (chat_spell->chat, + &(chat_spell->start), + &(chat_spell->end), + gtk_menu_item_get_label (menu_item)); +} + +static GtkWidget* +chat_spelling_build_menu (EmpathyChatSpell *chat_spell) +{ + GtkWidget *menu, *menu_item; + GList *suggestions, *l; + + menu = gtk_menu_new (); + suggestions = empathy_spell_get_suggestions (chat_spell->word); + if (suggestions == NULL) { + menu_item = gtk_menu_item_new_with_label (_("(No Suggestions)")); + gtk_widget_set_sensitive (menu_item, FALSE); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); + } else { + for (l = suggestions; l; l = l->next) { + menu_item = gtk_menu_item_new_with_label (l->data); + g_signal_connect (G_OBJECT (menu_item), + "activate", + G_CALLBACK (chat_spelling_menu_activate_cb), + chat_spell); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); + } + } + empathy_spell_free_suggestions (suggestions); + + gtk_widget_show_all (menu); + + return menu; } static void @@ -961,7 +988,8 @@ chat_input_populate_popup_cb (GtkTextView *view, GtkTextIter iter, start, end; GtkWidget *item; gchar *str = NULL; - EmpathyChatSpell *chat_spell; + EmpathyChatSpell *chat_spell; + GtkWidget *spell_menu; EmpathySmileyManager *smiley_manager; GtkWidget *smiley_menu; GtkWidget *image; @@ -1026,14 +1054,14 @@ chat_input_populate_popup_cb (GtkTextView *view, gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); - item = gtk_image_menu_item_new_with_mnemonic (_("_Check Word Spelling...")); + item = gtk_image_menu_item_new_with_mnemonic (_("_Spelling Suggestions")); image = gtk_image_new_from_icon_name (GTK_STOCK_SPELL_CHECK, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); - g_signal_connect (item, - "activate", - G_CALLBACK (chat_text_check_word_spelling_cb), - chat_spell); + + spell_menu = chat_spelling_build_menu (chat_spell); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), spell_menu); + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); } @@ -1139,10 +1167,6 @@ chat_members_changed_cb (EmpathyTpChat *tp_chat, if (priv->block_events_timeout_id == 0) { gchar *str; - empathy_contact_run_until_ready (contact, - EMPATHY_CONTACT_READY_NAME, - NULL); - if (is_member) { str = g_strdup_printf (_("%s has joined the room"), empathy_contact_get_name (contact)); @@ -1434,13 +1458,26 @@ chat_finalize (GObject *object) chat_composing_remove_timeout (chat); g_signal_handlers_disconnect_by_func (priv->account_manager, - chat_connection_changed_cb, object); + chat_new_connection_cb, object); g_object_unref (priv->account_manager); g_object_unref (priv->log_manager); if (priv->tp_chat) { - g_signal_handler_disconnect (priv->tp_chat, priv->tp_chat_destroy_handler); + g_signal_handlers_disconnect_by_func (priv->tp_chat, + chat_destroy_cb, chat); + g_signal_handlers_disconnect_by_func (priv->tp_chat, + chat_message_received_cb, chat); + g_signal_handlers_disconnect_by_func (priv->tp_chat, + chat_send_error_cb, chat); + g_signal_handlers_disconnect_by_func (priv->tp_chat, + chat_state_changed_cb, chat); + g_signal_handlers_disconnect_by_func (priv->tp_chat, + chat_property_changed_cb, chat); + g_signal_handlers_disconnect_by_func (priv->tp_chat, + chat_members_changed_cb, chat); + g_signal_handlers_disconnect_by_func (priv->tp_chat, + chat_remote_contact_changed_cb, chat); empathy_tp_chat_close (priv->tp_chat); g_object_unref (priv->tp_chat); } @@ -1578,8 +1615,8 @@ empathy_chat_init (EmpathyChat *chat) priv->account_manager = empathy_account_manager_dup_singleton (); g_signal_connect (priv->account_manager, - "account-connection-changed", - G_CALLBACK (chat_connection_changed_cb), + "new-connection", + G_CALLBACK (chat_new_connection_cb), chat); /* Block events for some time to avoid having "has come online" or @@ -1613,6 +1650,7 @@ empathy_chat_set_tp_chat (EmpathyChat *chat, EmpathyTpChat *tp_chat) { EmpathyChatPriv *priv = GET_PRIV (chat); + TpConnection *connection; g_return_if_fail (EMPATHY_IS_CHAT (chat)); g_return_if_fail (EMPATHY_IS_TP_CHAT (tp_chat)); @@ -1627,8 +1665,14 @@ empathy_chat_set_tp_chat (EmpathyChat *chat, } priv->tp_chat = g_object_ref (tp_chat); - priv->account = g_object_ref (empathy_tp_chat_get_account (tp_chat)); + connection = empathy_tp_chat_get_connection (priv->tp_chat); + priv->account = empathy_account_manager_get_account (priv->account_manager, + connection); + g_object_ref (priv->account); + g_signal_connect (tp_chat, "destroy", + G_CALLBACK (chat_destroy_cb), + chat); g_signal_connect (tp_chat, "message-received", G_CALLBACK (chat_message_received_cb), chat); @@ -1647,10 +1691,6 @@ empathy_chat_set_tp_chat (EmpathyChat *chat, g_signal_connect_swapped (tp_chat, "notify::remote-contact", G_CALLBACK (chat_remote_contact_changed_cb), chat); - priv->tp_chat_destroy_handler = - g_signal_connect (tp_chat, "destroy", - G_CALLBACK (chat_destroy_cb), - chat); chat_remote_contact_changed_cb (chat); @@ -1730,20 +1770,6 @@ empathy_chat_get_remote_contact (EmpathyChat *chat) return priv->remote_contact; } -guint -empathy_chat_get_members_count (EmpathyChat *chat) -{ - EmpathyChatPriv *priv = GET_PRIV (chat); - - g_return_val_if_fail (EMPATHY_IS_CHAT (chat), 0); - - if (priv->tp_chat) { - return empathy_tp_chat_get_members_count (priv->tp_chat); - } - - return 0; -} - GtkWidget * empathy_chat_get_contact_menu (EmpathyChat *chat) { diff --git a/libempathy-gtk/empathy-chat.h b/libempathy-gtk/empathy-chat.h index 6b7fcf26e..f61ce4154 100644 --- a/libempathy-gtk/empathy-chat.h +++ b/libempathy-gtk/empathy-chat.h @@ -71,7 +71,6 @@ const gchar * empathy_chat_get_id (EmpathyChat *chat); const gchar * empathy_chat_get_name (EmpathyChat *chat); const gchar * empathy_chat_get_subject (EmpathyChat *chat); EmpathyContact * empathy_chat_get_remote_contact (EmpathyChat *chat); -guint empathy_chat_get_members_count (EmpathyChat *chat); GtkWidget * empathy_chat_get_contact_menu (EmpathyChat *chat); void empathy_chat_clear (EmpathyChat *chat); void empathy_chat_scroll_down (EmpathyChat *chat); diff --git a/libempathy-gtk/empathy-contact-dialogs.c b/libempathy-gtk/empathy-contact-dialogs.c index 72b5b28b3..056ec2d85 100644 --- a/libempathy-gtk/empathy-contact-dialogs.c +++ b/libempathy-gtk/empathy-contact-dialogs.c @@ -30,6 +30,7 @@ #include <libmissioncontrol/mission-control.h> #include <libempathy/empathy-contact-manager.h> +#include <libempathy/empathy-account-manager.h> #include <libempathy/empathy-contact-list.h> #include <libempathy/empathy-utils.h> @@ -39,9 +40,10 @@ static GList *subscription_dialogs = NULL; static GList *information_dialogs = NULL; +static GList *edit_dialogs = NULL; +static GtkWidget *personal_dialog = NULL; static GtkWidget *new_contact_dialog = NULL; - static gint contact_dialogs_find (GtkDialog *dialog, EmpathyContact *contact) @@ -114,6 +116,7 @@ empathy_subscription_dialog_show (EmpathyContact *contact, g_free (filename); g_object_unref (gui); + /* Contact info widget */ contact_widget = empathy_contact_widget_new (contact, EMPATHY_CONTACT_WIDGET_EDIT_ALIAS | EMPATHY_CONTACT_WIDGET_EDIT_GROUPS); @@ -123,7 +126,6 @@ empathy_subscription_dialog_show (EmpathyContact *contact, 0); gtk_widget_show (contact_widget); - g_object_set_data (G_OBJECT (dialog), "contact_widget", contact_widget); subscription_dialogs = g_list_prepend (subscription_dialogs, dialog); @@ -143,25 +145,22 @@ empathy_subscription_dialog_show (EmpathyContact *contact, */ static void -contact_information_response_cb (GtkDialog *dialog, - gint response, - GtkWidget *contact_widget) +contact_dialogs_response_cb (GtkDialog *dialog, + gint response, + GList **dialogs) { - information_dialogs = g_list_remove (information_dialogs, dialog); + *dialogs = g_list_remove (*dialogs, dialog); gtk_widget_destroy (GTK_WIDGET (dialog)); } void empathy_contact_information_dialog_show (EmpathyContact *contact, - GtkWindow *parent, - gboolean edit, - gboolean is_user) + GtkWindow *parent) { - GtkWidget *dialog; - GtkWidget *button; - GtkWidget *contact_widget; - GList *l; - EmpathyContactWidgetFlags flags = 0; + GtkWidget *dialog; + GtkWidget *button; + GtkWidget *contact_widget; + GList *l; g_return_if_fail (EMPATHY_IS_CONTACT (contact)); @@ -177,15 +176,7 @@ empathy_contact_information_dialog_show (EmpathyContact *contact, dialog = gtk_dialog_new (); gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); - if (is_user) { - gtk_window_set_title (GTK_WINDOW (dialog), _("Personal Information")); - } - else if (edit) { - gtk_window_set_title (GTK_WINDOW (dialog), _("Edit Contact Information")); - } - else { - gtk_window_set_title (GTK_WINDOW (dialog), _("Contact Information")); - } + gtk_window_set_title (GTK_WINDOW (dialog), _("Edit Contact Information")); /* Close button */ button = gtk_button_new_with_label (GTK_STOCK_CLOSE); @@ -198,34 +189,79 @@ empathy_contact_information_dialog_show (EmpathyContact *contact, gtk_widget_show (button); /* Contact info widget */ - if (edit) { - flags |= EMPATHY_CONTACT_WIDGET_EDIT_ALIAS; - } - if (is_user) { - flags |= EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT; - flags |= EMPATHY_CONTACT_WIDGET_EDIT_AVATAR; + contact_widget = empathy_contact_widget_new (contact, + EMPATHY_CONTACT_WIDGET_EDIT_NONE); + gtk_container_set_border_width (GTK_CONTAINER (contact_widget), 8); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), + contact_widget, + TRUE, TRUE, 0); + gtk_widget_show (contact_widget); + + g_object_set_data (G_OBJECT (dialog), "contact_widget", contact_widget); + information_dialogs = g_list_prepend (information_dialogs, dialog); + + g_signal_connect (dialog, "response", + G_CALLBACK (contact_dialogs_response_cb), + &information_dialogs); + + if (parent) { + gtk_window_set_transient_for (GTK_WINDOW (dialog), parent); } - if (!is_user && edit) { - flags |= EMPATHY_CONTACT_WIDGET_EDIT_GROUPS; + + gtk_widget_show (dialog); +} + +void +empathy_contact_edit_dialog_show (EmpathyContact *contact, + GtkWindow *parent) +{ + GtkWidget *dialog; + GtkWidget *button; + GtkWidget *contact_widget; + GList *l; + + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + + l = g_list_find_custom (edit_dialogs, + contact, + (GCompareFunc) contact_dialogs_find); + if (l) { + gtk_window_present (GTK_WINDOW (l->data)); + return; } - contact_widget = empathy_contact_widget_new (contact, flags); + + /* Create dialog */ + dialog = gtk_dialog_new (); + gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); + gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); + gtk_window_set_title (GTK_WINDOW (dialog), _("Edit Contact Information")); + + /* Close button */ + button = gtk_button_new_with_label (GTK_STOCK_CLOSE); + gtk_button_set_use_stock (GTK_BUTTON (button), TRUE); + gtk_dialog_add_action_widget (GTK_DIALOG (dialog), + button, + GTK_RESPONSE_CLOSE); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_window_set_default (GTK_WINDOW (dialog), button); + gtk_widget_show (button); + + /* Contact info widget */ + contact_widget = empathy_contact_widget_new (contact, + EMPATHY_CONTACT_WIDGET_EDIT_ALIAS | + EMPATHY_CONTACT_WIDGET_EDIT_GROUPS); gtk_container_set_border_width (GTK_CONTAINER (contact_widget), 8); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), contact_widget, TRUE, TRUE, 0); - if (flags & EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT) { - empathy_contact_widget_set_account_filter (contact_widget, - empathy_account_chooser_filter_is_connected, - NULL); - } gtk_widget_show (contact_widget); g_object_set_data (G_OBJECT (dialog), "contact_widget", contact_widget); - information_dialogs = g_list_prepend (information_dialogs, dialog); + edit_dialogs = g_list_prepend (edit_dialogs, dialog); g_signal_connect (dialog, "response", - G_CALLBACK (contact_information_response_cb), - contact_widget); + G_CALLBACK (contact_dialogs_response_cb), + &edit_dialogs); if (parent) { gtk_window_set_transient_for (GTK_WINDOW (dialog), parent); @@ -234,6 +270,58 @@ empathy_contact_information_dialog_show (EmpathyContact *contact, gtk_widget_show (dialog); } +void +empathy_contact_personal_dialog_show (GtkWindow *parent) +{ + GtkWidget *button; + GtkWidget *contact_widget; + + if (personal_dialog) { + gtk_window_present (GTK_WINDOW (personal_dialog)); + return; + } + + /* Create dialog */ + personal_dialog = gtk_dialog_new (); + gtk_dialog_set_has_separator (GTK_DIALOG (personal_dialog), FALSE); + gtk_window_set_resizable (GTK_WINDOW (personal_dialog), FALSE); + gtk_window_set_title (GTK_WINDOW (personal_dialog), _("Personal Information")); + + /* Close button */ + button = gtk_button_new_with_label (GTK_STOCK_CLOSE); + gtk_button_set_use_stock (GTK_BUTTON (button), TRUE); + gtk_dialog_add_action_widget (GTK_DIALOG (personal_dialog), + button, + GTK_RESPONSE_CLOSE); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_window_set_default (GTK_WINDOW (personal_dialog), button); + gtk_widget_show (button); + + /* Contact info widget */ + contact_widget = empathy_contact_widget_new (NULL, + EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT | + EMPATHY_CONTACT_WIDGET_EDIT_ALIAS | + EMPATHY_CONTACT_WIDGET_EDIT_AVATAR); + gtk_container_set_border_width (GTK_CONTAINER (contact_widget), 8); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (personal_dialog)->vbox), + contact_widget, + TRUE, TRUE, 0); + empathy_contact_widget_set_account_filter (contact_widget, + empathy_account_chooser_filter_is_connected, NULL); + gtk_widget_show (contact_widget); + + g_signal_connect (personal_dialog, "response", + G_CALLBACK (gtk_widget_destroy), NULL); + g_object_add_weak_pointer (G_OBJECT (personal_dialog), + (gpointer) &personal_dialog); + + if (parent) { + gtk_window_set_transient_for (GTK_WINDOW (personal_dialog), parent); + } + + gtk_widget_show (personal_dialog); +} + /* * New contact dialog */ @@ -242,12 +330,23 @@ static gboolean can_add_contact_to_account (McAccount *account, gpointer user_data) { - EmpathyContactManager *mgr; + EmpathyAccountManager *account_manager; + EmpathyContactManager *contact_manager; + TpConnection *connection; gboolean result; - mgr = empathy_contact_manager_dup_singleton (); - result = empathy_contact_manager_can_add (mgr, account); - g_object_unref (mgr); + account_manager = empathy_account_manager_dup_singleton (); + connection = empathy_account_manager_get_connection (account_manager, + account); + if (!connection) { + g_object_unref (account_manager); + return FALSE; + } + + contact_manager = empathy_contact_manager_dup_singleton (); + result = empathy_contact_manager_can_add (contact_manager, connection); + g_object_unref (contact_manager); + g_object_unref (account_manager); return result; } diff --git a/libempathy-gtk/empathy-contact-dialogs.h b/libempathy-gtk/empathy-contact-dialogs.h index e375f959c..c714c6b96 100644 --- a/libempathy-gtk/empathy-contact-dialogs.h +++ b/libempathy-gtk/empathy-contact-dialogs.h @@ -29,12 +29,13 @@ G_BEGIN_DECLS void empathy_subscription_dialog_show (EmpathyContact *contact, - GtkWindow *parent); + GtkWindow *parent); void empathy_contact_information_dialog_show (EmpathyContact *contact, - GtkWindow *parent, - gboolean edit, - gboolean is_user); -void empathy_new_contact_dialog_show (GtkWindow *parent); + GtkWindow *parent); +void empathy_contact_edit_dialog_show (EmpathyContact *contact, + GtkWindow *parent); +void empathy_contact_personal_dialog_show (GtkWindow *parent); +void empathy_new_contact_dialog_show (GtkWindow *parent); G_END_DECLS diff --git a/libempathy-gtk/empathy-contact-list-view.c b/libempathy-gtk/empathy-contact-list-view.c index 3fdc7b327..ca224f526 100644 --- a/libempathy-gtk/empathy-contact-list-view.c +++ b/libempathy-gtk/empathy-contact-list-view.c @@ -31,10 +31,12 @@ #include <gdk/gdkkeysyms.h> #include <gtk/gtk.h> +#include <telepathy-glib/util.h> #include <libmissioncontrol/mc-account.h> +#include <libempathy/empathy-account-manager.h> #include <libempathy/empathy-call-factory.h> -#include <libempathy/empathy-contact-factory.h> +#include <libempathy/empathy-tp-contact-factory.h> #include <libempathy/empathy-contact-list.h> #include <libempathy/empathy-contact-groups.h> #include <libempathy/empathy-dispatcher.h> @@ -122,8 +124,8 @@ contact_list_view_tooltip_destroy_cb (GtkWidget *widget, if (priv->tooltip_widget) { DEBUG ("Tooltip destroyed"); + g_object_unref (priv->tooltip_widget); priv->tooltip_widget = NULL; - g_object_unref (widget); } } @@ -188,8 +190,52 @@ OUT: return ret; } +typedef struct { + gchar *new_group; + gchar *old_group; + GdkDragAction action; +} DndGetContactData; + +static void +contact_list_view_dnd_get_contact_free (DndGetContactData *data) +{ + g_free (data->new_group); + g_free (data->old_group); + g_slice_free (DndGetContactData, data); +} + static void -contact_list_view_drag_data_received (GtkWidget *widget, +contact_list_view_drag_got_contact (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *view) +{ + EmpathyContactListViewPriv *priv = GET_PRIV (view); + DndGetContactData *data = user_data; + EmpathyContactList *list; + + if (error != NULL) { + DEBUG ("Error: %s", error->message); + return; + } + + DEBUG ("contact %s (%d) dragged from '%s' to '%s'", + empathy_contact_get_id (contact), + empathy_contact_get_handle (contact), + data->old_group, data->new_group); + + list = empathy_contact_list_store_get_list_iface (priv->store); + if (data->new_group) { + empathy_contact_list_add_to_group (list, contact, data->new_group); + } + if (data->old_group && data->action == GDK_ACTION_MOVE) { + empathy_contact_list_remove_from_group (list, contact, data->old_group); + } +} + +static void +contact_list_view_drag_data_received (GtkWidget *view, GdkDragContext *context, gint x, gint y, @@ -198,88 +244,102 @@ contact_list_view_drag_data_received (GtkWidget *widget, guint time) { EmpathyContactListViewPriv *priv; - EmpathyContactList *list; - EmpathyContactFactory *factory; + EmpathyAccountManager *account_manager; + EmpathyTpContactFactory *factory = NULL; McAccount *account; GtkTreeModel *model; - GtkTreePath *path; GtkTreeViewDropPosition position; - EmpathyContact *contact = NULL; + GtkTreePath *path; const gchar *id; - gchar **strv; + gchar **strv = NULL; + const gchar *account_id; + const gchar *contact_id; gchar *new_group = NULL; gchar *old_group = NULL; + DndGetContactData *data; gboolean is_row; + gboolean success = TRUE; - priv = GET_PRIV (widget); - - id = (const gchar*) selection->data; - DEBUG ("Received %s%s drag & drop contact from roster with id:'%s'", - context->action == GDK_ACTION_MOVE ? "move" : "", - context->action == GDK_ACTION_COPY ? "copy" : "", - id); + priv = GET_PRIV (view); + model = gtk_tree_view_get_model (GTK_TREE_VIEW (view)); - strv = g_strsplit (id, "/", 2); - factory = empathy_contact_factory_dup_singleton (); - account = mc_account_lookup (strv[0]); - if (account) { - contact = empathy_contact_factory_get_from_id (factory, - account, - strv[1]); - g_object_unref (account); - } - g_object_unref (factory); - g_strfreev (strv); + /* Get destination group information. */ + is_row = gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (view), + x, + y, + &path, + &position); - if (!contact) { - DEBUG ("No contact found associated with drag & drop"); - return; + if (is_row) { + new_group = empathy_contact_list_store_get_parent_group (model, + path, NULL); + gtk_tree_path_free (path); } - empathy_contact_run_until_ready (contact, - EMPATHY_CONTACT_READY_HANDLE, - NULL); - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget)); - /* Get source group information. */ if (priv->drag_row) { path = gtk_tree_row_reference_get_path (priv->drag_row); if (path) { - old_group = empathy_contact_list_store_get_parent_group (model, path, NULL); + old_group = empathy_contact_list_store_get_parent_group ( + model, path, NULL); gtk_tree_path_free (path); } } - /* Get destination group information. */ - is_row = gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget), - x, - y, - &path, - &position); - - if (is_row) { - new_group = empathy_contact_list_store_get_parent_group (model, path, NULL); - gtk_tree_path_free (path); + if (!tp_strdiff (old_group, new_group)) { + g_free (new_group); + g_free (old_group); + goto OUT; } - DEBUG ("contact %s (%d) dragged from '%s' to '%s'", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact), - old_group, new_group); + id = (const gchar*) selection->data; + DEBUG ("Received %s%s drag & drop contact from roster with id:'%s'", + context->action == GDK_ACTION_MOVE ? "move" : "", + context->action == GDK_ACTION_COPY ? "copy" : "", + id); - list = empathy_contact_list_store_get_list_iface (priv->store); - if (new_group) { - empathy_contact_list_add_to_group (list, contact, new_group); + strv = g_strsplit (id, "/", 2); + account_id = strv[0]; + contact_id = strv[1]; + account = mc_account_lookup (account_id); + if (account) { + TpConnection *connection; + + /* FIXME: We assume we have already an account manager */ + account_manager = empathy_account_manager_dup_singleton (); + connection = empathy_account_manager_get_connection (account_manager, + account); + if (connection) { + factory = empathy_tp_contact_factory_dup_singleton (connection); + } + g_object_unref (account_manager); } - if (old_group && context->action == GDK_ACTION_MOVE) { - empathy_contact_list_remove_from_group (list, contact, old_group); + + if (!factory) { + DEBUG ("Failed to get factory for account '%s'", account_id); + success = FALSE; + g_free (new_group); + g_free (old_group); + goto OUT; } - g_free (old_group); - g_free (new_group); + data = g_slice_new0 (DndGetContactData); + data->new_group = new_group; + data->old_group = old_group; + data->action = context->action; - gtk_drag_finish (context, TRUE, FALSE, GDK_CURRENT_TIME); + /* FIXME: We should probably wait for the cb before calling + * gtk_drag_finish */ + empathy_tp_contact_factory_get_from_id (factory, contact_id, + contact_list_view_drag_got_contact, + data, (GDestroyNotify) contact_list_view_dnd_get_contact_free, + G_OBJECT (view)); + + g_object_unref (factory); + +OUT: + g_strfreev (strv); + gtk_drag_finish (context, success, FALSE, GDK_CURRENT_TIME); } static gboolean @@ -414,7 +474,7 @@ contact_list_view_drag_data_get (GtkWidget *widget, gtk_tree_path_free (src_path); - contact = empathy_contact_list_view_get_selected (EMPATHY_CONTACT_LIST_VIEW (widget)); + contact = empathy_contact_list_view_dup_selected (EMPATHY_CONTACT_LIST_VIEW (widget)); if (!contact) { return; } @@ -1158,7 +1218,7 @@ empathy_contact_list_view_new (EmpathyContactListStore *store, } EmpathyContact * -empathy_contact_list_view_get_selected (EmpathyContactListView *view) +empathy_contact_list_view_dup_selected (EmpathyContactListView *view) { EmpathyContactListViewPriv *priv; GtkTreeSelection *selection; @@ -1324,7 +1384,7 @@ contact_list_view_remove_activate_cb (GtkMenuItem *menuitem, EmpathyContactListViewPriv *priv = GET_PRIV (view); EmpathyContact *contact; - contact = empathy_contact_list_view_get_selected (view); + contact = empathy_contact_list_view_dup_selected (view); if (contact) { gchar *text; @@ -1357,7 +1417,7 @@ empathy_contact_list_view_get_contact_menu (EmpathyContactListView *view) g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view), NULL); - contact = empathy_contact_list_view_get_selected (view); + contact = empathy_contact_list_view_dup_selected (view); if (!contact) { return NULL; } diff --git a/libempathy-gtk/empathy-contact-list-view.h b/libempathy-gtk/empathy-contact-list-view.h index 82990d64f..bb6766c4a 100644 --- a/libempathy-gtk/empathy-contact-list-view.h +++ b/libempathy-gtk/empathy-contact-list-view.h @@ -70,7 +70,7 @@ GType empathy_contact_list_view_get_type (void) G EmpathyContactListView * empathy_contact_list_view_new (EmpathyContactListStore *store, EmpathyContactListFeatureFlags list_features, EmpathyContactFeatureFlags contact_features); -EmpathyContact * empathy_contact_list_view_get_selected (EmpathyContactListView *view); +EmpathyContact * empathy_contact_list_view_dup_selected (EmpathyContactListView *view); gchar * empathy_contact_list_view_get_selected_group (EmpathyContactListView *view); GtkWidget * empathy_contact_list_view_get_contact_menu (EmpathyContactListView *view); GtkWidget * empathy_contact_list_view_get_group_menu (EmpathyContactListView *view); diff --git a/libempathy-gtk/empathy-contact-menu.c b/libempathy-gtk/empathy-contact-menu.c index 9cd9a0b9f..a3cf1da26 100644 --- a/libempathy-gtk/empathy-contact-menu.c +++ b/libempathy-gtk/empathy-contact-menu.c @@ -236,7 +236,7 @@ empathy_contact_file_transfer_menu_item_new (EmpathyContact *contact) static void contact_info_menu_item_activate_cb (EmpathyContact *contact) { - empathy_contact_information_dialog_show (contact, NULL, FALSE, FALSE); + empathy_contact_information_dialog_show (contact, NULL); } GtkWidget * @@ -263,7 +263,7 @@ empathy_contact_info_menu_item_new (EmpathyContact *contact) static void contact_edit_menu_item_activate_cb (EmpathyContact *contact) { - empathy_contact_information_dialog_show (contact, NULL, TRUE, FALSE); + empathy_contact_edit_dialog_show (contact, NULL); } GtkWidget * diff --git a/libempathy-gtk/empathy-contact-selector.c b/libempathy-gtk/empathy-contact-selector.c index 539629a23..f4a302c5b 100644 --- a/libempathy-gtk/empathy-contact-selector.c +++ b/libempathy-gtk/empathy-contact-selector.c @@ -31,6 +31,23 @@ #include "empathy-contact-selector.h" +/** + * SECTION:empathy-contact-selector + * @title:EmpathyContactSelector + * @short_description: A widget used to choose from a list of contacts. + * @include: libempathy-gtk/empathy-contact-selector.h + * + * #EmpathyContactSelector is a widget which extends #GtkComboBox to provide + * a chooser of available contacts. + */ + +/** + * EmpathyContactSelector: + * @parent: parent object + * + * Widget which extends #GtkComboBox to provide a chooser of available contacts. + */ + G_DEFINE_TYPE (EmpathyContactSelector, empathy_contact_selector, GTK_TYPE_COMBO_BOX) @@ -320,14 +337,27 @@ empathy_contact_selector_class_init (EmpathyContactSelectorClass *klass) object_class->get_property = contact_selector_get_property; g_type_class_add_private (klass, sizeof (EmpathyContactSelectorPriv)); + /** + * EmpathyContactSelector:contact-list: + * + * An #EmpathyContactList containing the contacts for the + * #EmpathyContactSelector. + */ g_object_class_install_property (object_class, PROP_CONTACT_LIST, g_param_spec_object ("contact-list", "contact list", "contact list", EMPATHY_TYPE_CONTACT_LIST, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); } -/* public methods */ - +/** + * empathy_contact_selector_new: + * @contact_list: an #EmpathyContactList containing the contacts to list in + * the contact selector + * + * Creates a new #EmpathyContactSelector. + * + * Return value: A new #EmpathyContactSelector + */ GtkWidget * empathy_contact_selector_new (EmpathyContactList *contact_list) { @@ -337,6 +367,16 @@ empathy_contact_selector_new (EmpathyContactList *contact_list) "contact-list", contact_list, NULL)); } +/** + * empathy_contact_selector_dup_selected: + * @selector: An #EmpathyContactSelector + * + * Returns a new reference to the contact which is currently selected in + * @selector, or %NULL if there is no contact selected. The returned contact + * should be unrefed with g_object_unref() when finished with. + * + * Return value: A new reference to the contact currently selected, or %NULL + */ EmpathyContact * empathy_contact_selector_dup_selected (EmpathyContactSelector *selector) { @@ -390,6 +430,19 @@ contact_selector_filter_visible_func (GtkTreeModel *model, return visible; } +/** + * empathy_contact_selector_set_visible: + * @selector: an #EmpathyContactSelector + * @func: an #EmpathyContactSelectorFilterFunc to filter the contacts + * @user_data: data to pass to @func or %NULL + * + * Sets a filter on the @selector so only contacts that return %TRUE + * when passed into @func are visible. + * + * A typical usage for this function would be to only show contacts that + * can send or receive files. In this case, one could use the + * empathy_contact_can_send_files() function + */ void empathy_contact_selector_set_visible (EmpathyContactSelector *selector, EmpathyContactSelectorFilterFunc func, @@ -407,3 +460,14 @@ empathy_contact_selector_set_visible (EmpathyContactSelector *selector, gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->model)); } + +/** + * EmpathyContactSelectorFilterFunc: + * @contact: an #EmpathyContact + * @user_data: user data or %NULL + * + * A function which decides whether the contact indicated by @contact + * is visible. + * + * Return value: whether @contact is visible + */ diff --git a/libempathy-gtk/empathy-contact-selector.h b/libempathy-gtk/empathy-contact-selector.h index f7af92f2c..205b9e411 100644 --- a/libempathy-gtk/empathy-contact-selector.h +++ b/libempathy-gtk/empathy-contact-selector.h @@ -49,6 +49,8 @@ typedef struct _EmpathyContactSelectorClass EmpathyContactSelectorClass; struct _EmpathyContactSelector { GtkComboBox parent; + + /*<private>*/ gpointer priv; }; diff --git a/libempathy-gtk/empathy-contact-widget.c b/libempathy-gtk/empathy-contact-widget.c index ef259b0a4..0821066fa 100644 --- a/libempathy-gtk/empathy-contact-widget.c +++ b/libempathy-gtk/empathy-contact-widget.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * Copyright (C) 2007-2008 Collabora Ltd. + * Copyright (C) 2007-2009 Collabora Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -30,7 +30,7 @@ #include <libmissioncontrol/mc-account.h> #include <telepathy-glib/util.h> -#include <libempathy/empathy-contact-factory.h> +#include <libempathy/empathy-tp-contact-factory.h> #include <libempathy/empathy-contact-manager.h> #include <libempathy/empathy-contact-list.h> #include <libempathy/empathy-utils.h> @@ -44,12 +44,31 @@ #define DEBUG_FLAG EMPATHY_DEBUG_CONTACT #include <libempathy/empathy-debug.h> +/** + * SECTION:empathy-contact-widget + * @title:EmpathyContactWidget + * @short_description: A widget used to display and edit details about a contact + * @include: libempathy-empathy-contact-widget.h + * + * #EmpathyContactWidget is a widget which displays appropriate widgets + * with details about a contact, also allowing changing these details, + * if desired. + */ + +/** + * EmpathyContactWidget: + * @parent: parent object + * + * Widget which displays appropriate widgets with details about a contact, + * also allowing changing these details, if desired. + */ + /* Delay before updating the widget when the id entry changed (seconds) */ #define ID_CHANGED_TIMEOUT 1 typedef struct { - EmpathyContactFactory *factory; + EmpathyTpContactFactory *factory; EmpathyContactManager *manager; EmpathyContact *contact; EmpathyContactWidgetFlags flags; @@ -106,8 +125,6 @@ static void contact_widget_contact_update (EmpathyContactWidget *information); static void contact_widget_change_contact (EmpathyContactWidget *information); static void contact_widget_avatar_changed_cb (EmpathyAvatarChooser *chooser, EmpathyContactWidget *information); -static void contact_widget_account_changed_cb (GtkComboBox *widget, - EmpathyContactWidget *information); static gboolean contact_widget_id_focus_out_cb (GtkWidget *widget, GdkEventFocus *event, EmpathyContactWidget *information); static gboolean contact_widget_entry_alias_focus_event_cb ( @@ -153,6 +170,15 @@ enum COL_COUNT }; +/** + * empathy_contact_widget_new: + * @contact: an #EmpathyContact + * @flags: #EmpathyContactWidgetFlags for the new contact widget + * + * Creates a new #EmpathyContactWidget. + * + * Return value: a new #EmpathyContactWidget + */ GtkWidget * empathy_contact_widget_new (EmpathyContact *contact, EmpathyContactWidgetFlags flags) @@ -161,9 +187,10 @@ empathy_contact_widget_new (EmpathyContact *contact, GtkBuilder *gui; gchar *filename; + g_return_val_if_fail (contact == NULL || EMPATHY_IS_CONTACT (contact), NULL); + information = g_slice_new0 (EmpathyContactWidget); information->flags = flags; - information->factory = empathy_contact_factory_dup_singleton (); filename = empathy_file_lookup ("empathy-contact-widget.ui", "libempathy-gtk"); @@ -206,12 +233,25 @@ empathy_contact_widget_new (EmpathyContact *contact, contact_widget_details_setup (information); contact_widget_client_setup (information); - contact_widget_set_contact (information, contact); + if (contact != NULL) + contact_widget_set_contact (information, contact); + + else if (information->flags & EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT || + information->flags & EMPATHY_CONTACT_WIDGET_EDIT_ID) + contact_widget_change_contact (information); return empathy_builder_unref_and_keep_widget (gui, information->vbox_contact_widget); } +/** + * empathy_contact_widget_get_contact: + * @widget: an #EmpathyContactWidget + * + * Get the #EmpathyContact related with the #EmpathyContactWidget @widget. + * + * Returns: the #EmpathyContact associated with @widget + */ EmpathyContact * empathy_contact_widget_get_contact (GtkWidget *widget) { @@ -226,6 +266,13 @@ empathy_contact_widget_get_contact (GtkWidget *widget) return information->contact; } +/** + * empathy_contact_widget_set_contact: + * @widget: an #EmpathyContactWidget + * @contact: a different #EmpathyContact + * + * Change the #EmpathyContact related with the #EmpathyContactWidget @widget. + */ void empathy_contact_widget_set_contact (GtkWidget *widget, EmpathyContact *contact) @@ -242,6 +289,15 @@ empathy_contact_widget_set_contact (GtkWidget *widget, contact_widget_set_contact (information, contact); } +/** + * empathy_contact_widget_set_account_filter: + * @widget: an #EmpathyContactWidget + * @filter: a #EmpathyAccountChooserFilterFunc + * @user_data: user data to pass to @filter, or %NULL + * + * Set a filter on the #EmpathyAccountChooser included in the + * #EmpathyContactWidget. + */ void empathy_contact_widget_set_account_filter ( GtkWidget *widget, @@ -272,10 +328,6 @@ contact_widget_destroy_cb (GtkWidget *widget, { g_source_remove (information->widget_id_timeout); } - if (information->factory) - { - g_object_unref (information->factory); - } if (information->manager) { g_object_unref (information->manager); @@ -299,7 +351,9 @@ contact_widget_remove_contact (EmpathyContactWidget *information) contact_widget_groups_notify_cb, information); g_object_unref (information->contact); + g_object_unref (information->factory); information->contact = NULL; + information->factory = NULL; } } @@ -312,7 +366,13 @@ contact_widget_set_contact (EmpathyContactWidget *information, contact_widget_remove_contact (information); if (contact) + { + TpConnection *connection; + + connection = empathy_contact_get_connection (contact); information->contact = g_object_ref (contact); + information->factory = empathy_tp_contact_factory_dup_singleton (connection); + } /* Update information for widgets */ contact_widget_contact_update (information); @@ -491,10 +551,10 @@ static void update_avatar_chooser_account_cb (EmpathyAccountChooser *account_chooser, EmpathyAvatarChooser *avatar_chooser) { - McAccount *account; + TpConnection *connection; - account = empathy_account_chooser_get_account (account_chooser); - g_object_set (avatar_chooser, "account", account, NULL); + connection = empathy_account_chooser_get_connection (account_chooser); + g_object_set (avatar_chooser, "connection", connection, NULL); } static void @@ -505,8 +565,8 @@ contact_widget_contact_setup (EmpathyContactWidget *information) { information->widget_account = empathy_account_chooser_new (); - g_signal_connect (information->widget_account, "changed", - G_CALLBACK (contact_widget_account_changed_cb), + g_signal_connect_swapped (information->widget_account, "changed", + G_CALLBACK (contact_widget_change_contact), information); } else @@ -636,12 +696,12 @@ contact_widget_contact_update (EmpathyContactWidget *information) if (account) { g_signal_handlers_block_by_func (information->widget_account, - contact_widget_account_changed_cb, + contact_widget_change_contact, information); empathy_account_chooser_set_account ( EMPATHY_ACCOUNT_CHOOSER (information->widget_account), account); g_signal_handlers_unblock_by_func (information->widget_account, - contact_widget_account_changed_cb, information); + contact_widget_change_contact, information); } } else @@ -683,83 +743,71 @@ contact_widget_contact_update (EmpathyContactWidget *information) } static void -contact_widget_change_contact_cb (EmpathyContact *contact, - const GError *error, - gpointer information, - GObject *weak_object) +contact_widget_got_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *weak_object) { - if (error) - DEBUG ("Error: %s", error->message); - else - contact_widget_set_contact (information, contact); - g_object_unref (contact); + EmpathyContactWidget *information = user_data; + + if (error != NULL) + { + DEBUG ("Error: %s", error->message); + return; + } + + contact_widget_set_contact (information, contact); } static void contact_widget_change_contact (EmpathyContactWidget *information) { - EmpathyContact *contact; - McAccount *account; + EmpathyTpContactFactory *factory; + TpConnection *connection; - account = empathy_account_chooser_get_account ( + connection = empathy_account_chooser_get_connection ( EMPATHY_ACCOUNT_CHOOSER (information->widget_account)); - if (!account) + if (!connection) return; + factory = empathy_tp_contact_factory_dup_singleton (connection); if (information->flags & EMPATHY_CONTACT_WIDGET_EDIT_ID) { const gchar *id; id = gtk_entry_get_text (GTK_ENTRY (information->widget_id)); - if (EMP_STR_EMPTY (id)) - return; - - contact = empathy_contact_factory_get_from_id (information->factory, - account, id); + if (!EMP_STR_EMPTY (id)) + { + empathy_tp_contact_factory_get_from_id (factory, id, + contact_widget_got_contact_cb, information, NULL, + G_OBJECT (information->vbox_contact_widget)); + } } else { - contact = empathy_contact_factory_get_user (information->factory, - account); - } - - if (contact) - { - /* Give the contact ref to the callback */ - empathy_contact_call_when_ready (contact, - EMPATHY_CONTACT_READY_HANDLE | - EMPATHY_CONTACT_READY_ID, - contact_widget_change_contact_cb, - information, NULL, + empathy_tp_contact_factory_get_from_handle (factory, + tp_connection_get_self_handle (connection), + contact_widget_got_contact_cb, information, NULL, G_OBJECT (information->vbox_contact_widget)); } + + g_object_unref (factory); } static void contact_widget_avatar_changed_cb (EmpathyAvatarChooser *chooser, EmpathyContactWidget *information) { - if (information->contact && empathy_contact_is_user (information->contact)) - { - McAccount *account; - const gchar *data; - gsize size; - const gchar *mime_type; - - account = empathy_contact_get_account (information->contact); - empathy_avatar_chooser_get_image_data ( - EMPATHY_AVATAR_CHOOSER (information->widget_avatar), - &data, &size, &mime_type); - empathy_contact_factory_set_avatar (information->factory, account, - data, size, mime_type); - } -} - -static void -contact_widget_account_changed_cb (GtkComboBox *widget, - EmpathyContactWidget *information) -{ - contact_widget_change_contact (information); + const gchar *data; + gsize size; + const gchar *mime_type; + + empathy_avatar_chooser_get_image_data ( + EMPATHY_AVATAR_CHOOSER (information->widget_avatar), + &data, &size, &mime_type); + empathy_tp_contact_factory_set_avatar (information->factory, + data, size, mime_type); } static gboolean @@ -781,7 +829,7 @@ contact_widget_entry_alias_focus_event_cb (GtkEditable *editable, const gchar *alias; alias = gtk_entry_get_text (GTK_ENTRY (editable)); - empathy_contact_factory_set_alias (information->factory, + empathy_tp_contact_factory_set_alias (information->factory, information->contact, alias); } diff --git a/libempathy-gtk/empathy-contact-widget.h b/libempathy-gtk/empathy-contact-widget.h index 4ba75e17f..0da5580a3 100644 --- a/libempathy-gtk/empathy-contact-widget.h +++ b/libempathy-gtk/empathy-contact-widget.h @@ -29,6 +29,27 @@ G_BEGIN_DECLS +/** + * EmpathyContactWidgetFlags: + * @EMPATHY_CONTACT_WIDGET_EDIT_NONE: Don't show any widgets to edit any details + * of the contact. This should be the option for widgets that merely display + * information about a contact. + * @EMPATHY_CONTACT_WIDGET_EDIT_ALIAS: Show a #GtkEntry allowing changes to the + * contact's alias. + * @EMPATHY_CONTACT_WIDGET_EDIT_AVATAR: Show an #EmpathyAvatarChooser allowing + * changes to the contact's avatar. + * @EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT: Show an #EmpathyAccountChooser allowing + * changes to the contact's account. + * @EMPATHY_CONTACT_WIDGET_EDIT_ID: Show a #GtkEntry allowing changes to the + * contact's identifier. + * @EMPATHY_CONTACT_WIDGET_EDIT_GROUPS: Show a widget to change the groups the + * contact is in. + * @EMPATHY_CONTACT_WIDGET_FOR_TOOLTIP: Make widgets more designed for a tooltip. + * For example, make widgets not selectable. + * + * Flags used when creating an #EmpathyContactWidget to specify which features + * should be available. + */ typedef enum { EMPATHY_CONTACT_WIDGET_EDIT_NONE = 0, diff --git a/libempathy-gtk/empathy-irc-network-dialog.c b/libempathy-gtk/empathy-irc-network-dialog.c index 89ee5b284..8f7f47bda 100644 --- a/libempathy-gtk/empathy-irc-network-dialog.c +++ b/libempathy-gtk/empathy-irc-network-dialog.c @@ -572,6 +572,7 @@ empathy_irc_network_dialog_show (EmpathyIrcNetwork *network, gtk_window_set_modal (GTK_WINDOW (dialog->dialog), TRUE); irc_network_dialog_network_update_buttons (dialog); + gtk_widget_show_all (dialog->dialog); return dialog->dialog; } diff --git a/libempathy-gtk/empathy-log-window.c b/libempathy-gtk/empathy-log-window.c index 2cec17783..13d9bcbd3 100644 --- a/libempathy-gtk/empathy-log-window.c +++ b/libempathy-gtk/empathy-log-window.c @@ -618,7 +618,7 @@ log_window_chats_populate (EmpathyLogWindow *window) GtkTreeIter iter; account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser_chats); - account = empathy_account_chooser_get_account (account_chooser); + account = empathy_account_chooser_dup_account (account_chooser); view = GTK_TREE_VIEW (window->treeview_chats); model = gtk_tree_view_get_model (view); diff --git a/libempathy-gtk/empathy-new-message-dialog.c b/libempathy-gtk/empathy-new-message-dialog.c index f6eb46a5f..3e6e3f11d 100644 --- a/libempathy-gtk/empathy-new-message-dialog.c +++ b/libempathy-gtk/empathy-new-message-dialog.c @@ -31,7 +31,7 @@ #include <libmissioncontrol/mission-control.h> #include <libempathy/empathy-call-factory.h> -#include <libempathy/empathy-contact-factory.h> +#include <libempathy/empathy-tp-contact-factory.h> #include <libempathy/empathy-contact-manager.h> #include <libempathy/empathy-dispatcher.h> #include <libempathy/empathy-utils.h> @@ -44,6 +44,16 @@ #include "empathy-new-message-dialog.h" #include "empathy-account-chooser.h" +/** + * SECTION:empathy-new-message-dialog + * @title: EmpathyNewMessageDialog + * @short_description: A dialog to show a new message + * @include: libempathy-gtk/empathy-new-message-dialog.h + * + * #EmpathyNewMessageDialog is a dialog which allows a text chat or + * call to be started with any contact on any enabled account. + */ + typedef struct { GtkWidget *dialog; GtkWidget *table_contact; @@ -65,48 +75,54 @@ new_message_dialog_account_changed_cb (GtkWidget *widget, EmpathyNewMessageDialog *dialog) { EmpathyAccountChooser *chooser; - McAccount *account; + TpConnection *connection; EmpathyTpContactList *contact_list; - GList *members, *l; + GList *members; GtkListStore *store; GtkEntryCompletion *completion; GtkTreeIter iter; gchar *tmpstr; - chooser = EMPATHY_ACCOUNT_CHOOSER (dialog->account_chooser); - account = empathy_account_chooser_get_account (chooser); - contact_list = empathy_contact_manager_get_list (dialog->contact_manager, - account); - members = empathy_contact_list_get_members (EMPATHY_CONTACT_LIST (contact_list)); + /* Remove completions */ completion = gtk_entry_get_completion (GTK_ENTRY (dialog->entry_id)); store = GTK_LIST_STORE (gtk_entry_completion_get_model (completion)); gtk_list_store_clear (store); - for (l = members; l; l = l->next) { - EmpathyContact *contact = l->data; + /* Get members of the new account */ + chooser = EMPATHY_ACCOUNT_CHOOSER (dialog->account_chooser); + connection = empathy_account_chooser_get_connection (chooser); + if (!connection) { + return; + } + contact_list = empathy_contact_manager_get_list (dialog->contact_manager, + connection); + members = empathy_contact_list_get_members (EMPATHY_CONTACT_LIST (contact_list)); + + /* Add members to the completion */ + while (members) { + EmpathyContact *contact = members->data; - if (!empathy_contact_is_online (contact)) { - continue; - } + if (empathy_contact_is_online (contact)) { + DEBUG ("Adding contact ID %s, Name %s", + empathy_contact_get_id (contact), + empathy_contact_get_name (contact)); - DEBUG ("Adding contact ID %s, Name %s", - empathy_contact_get_id (contact), - empathy_contact_get_name (contact)); + tmpstr = g_strdup_printf ("%s (%s)", + empathy_contact_get_name (contact), + empathy_contact_get_id (contact)); - tmpstr = g_strdup_printf ("%s (%s)", - empathy_contact_get_name (contact), - empathy_contact_get_id (contact)); + gtk_list_store_insert_with_values (store, &iter, -1, + COMPLETION_COL_TEXT, tmpstr, + COMPLETION_COL_ID, empathy_contact_get_id (contact), + COMPLETION_COL_NAME, empathy_contact_get_name (contact), + -1); - gtk_list_store_insert_with_values (store, &iter, -1, - COMPLETION_COL_TEXT, tmpstr, - COMPLETION_COL_ID, empathy_contact_get_id (contact), - COMPLETION_COL_NAME, empathy_contact_get_name (contact), - -1); + g_free (tmpstr); + } - g_free (tmpstr); + g_object_unref (contact); + members = g_list_delete_link (members, members); } - - g_object_unref (account); } static gboolean @@ -166,41 +182,51 @@ new_message_dialog_match_func (GtkEntryCompletion *completion, } static void +new_message_dialog_call_got_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + EmpathyCallFactory *call_factory; + + if (error != NULL) { + DEBUG ("Error: %s", error->message); + return; + } + + call_factory = empathy_call_factory_get(); + empathy_call_factory_new_call (call_factory, contact); +} + +static void new_message_dialog_response_cb (GtkWidget *widget, gint response, EmpathyNewMessageDialog *dialog) { - McAccount *account; + TpConnection *connection; const gchar *id; - account = empathy_account_chooser_get_account (EMPATHY_ACCOUNT_CHOOSER (dialog->account_chooser)); + connection = empathy_account_chooser_get_connection ( + EMPATHY_ACCOUNT_CHOOSER (dialog->account_chooser)); id = gtk_entry_get_text (GTK_ENTRY (dialog->entry_id)); - if (!account || EMP_STR_EMPTY (id)) { - if (account) { - g_object_unref (account); - } + if (!connection || EMP_STR_EMPTY (id)) { gtk_widget_destroy (widget); return; } if (response == 1) { - EmpathyContactFactory *factory; - EmpathyContact *contact; - EmpathyCallFactory *call_factory; - - factory = empathy_contact_factory_dup_singleton (); - contact = empathy_contact_factory_get_from_id (factory, account, id); + EmpathyTpContactFactory *factory; - call_factory = empathy_call_factory_get(); - empathy_call_factory_new_call (call_factory, contact); - - g_object_unref (contact); + factory = empathy_tp_contact_factory_dup_singleton (connection); + empathy_tp_contact_factory_get_from_id (factory, id, + new_message_dialog_call_got_contact_cb, + NULL, NULL, NULL); g_object_unref (factory); } else if (response == 2) { - empathy_dispatcher_chat_with_contact_id (account, id, NULL, NULL); + empathy_dispatcher_chat_with_contact_id (connection, id, NULL, NULL); } - g_object_unref (account); gtk_widget_destroy (widget); } @@ -226,6 +252,14 @@ new_message_dialog_destroy_cb (GtkWidget *widget, g_free (dialog); } +/** + * empathy_new_message_dialog_show: + * @parent: parent #GtkWindow of the dialog + * + * Create a new #EmpathyNewMessageDialog and show it. + * + * Return value: the new #EmpathyNewMessageDialog + */ GtkWidget * empathy_new_message_dialog_show (GtkWindow *parent) { diff --git a/libempathy-gtk/empathy-presence-chooser.c b/libempathy-gtk/empathy-presence-chooser.c index 8e9574bc5..f4a325b51 100644 --- a/libempathy-gtk/empathy-presence-chooser.c +++ b/libempathy-gtk/empathy-presence-chooser.c @@ -46,6 +46,24 @@ #include "empathy-ui-utils.h" #include "empathy-images.h" #include "empathy-presence-chooser.h" +#include "empathy-status-preset-dialog.h" + +/** + * SECTION:empathy-presence-chooser + * @title:EmpathyPresenceChooser + * @short_description: A widget used to change presence + * @include: libempathy-gtk/empathy-presence-chooser.h + * + * #EmpathyPresenceChooser is a widget which extends #GtkComboBoxEntry + * to change presence. + */ + +/** + * EmpathyAccountChooser: + * @parent: parent object + * + * Widget which extends #GtkComboBoxEntry to change presence. + */ /* Flashing delay for icons (milliseconds). */ #define FLASH_TIMEOUT 500 @@ -95,16 +113,6 @@ typedef struct { guint flash_timeout_id; } EmpathyPresenceChooserPriv; -typedef struct { - GtkWidget *dialog; - GtkWidget *checkbutton_save; - GtkWidget *comboboxentry_message; - GtkWidget *entry_message; - GtkWidget *combobox_status; - GtkTreeModel *model_status; -} CustomMessageDialog; - -static CustomMessageDialog *message_dialog = NULL; /* States to be listed in the menu. * Each state has a boolean telling if it can have custom message */ static guint states[] = {MC_PRESENCE_AVAILABLE, TRUE, @@ -130,7 +138,6 @@ static void presence_chooser_set_state (McPresence const gchar *status); static void presence_chooser_custom_activate_cb (GtkWidget *item, gpointer user_data); -static void presence_chooser_dialog_show (GtkWindow *parent); G_DEFINE_TYPE (EmpathyPresenceChooser, empathy_presence_chooser, GTK_TYPE_COMBO_BOX_ENTRY); @@ -180,7 +187,8 @@ presence_chooser_create_model (EmpathyPresenceChooser *self) if (states[i+1]) { /* Set custom messages if wanted */ - list = empathy_status_presets_get (states[i], 5); + list = empathy_status_presets_get (states[i], -1); + list = g_list_sort (list, (GCompareFunc) g_utf8_collate); for (l = list; l; l = l->next) { gtk_list_store_insert_with_values (store, NULL, -1, @@ -576,7 +584,7 @@ presence_chooser_changed_cb (GtkComboBox *self, gpointer user_data) } if (type == ENTRY_TYPE_EDIT_CUSTOM) { - GtkWidget *window; + GtkWidget *window, *dialog; presence_chooser_reset_status (EMPATHY_PRESENCE_CHOOSER (self)); @@ -586,7 +594,9 @@ presence_chooser_changed_cb (GtkComboBox *self, gpointer user_data) window = NULL; } - presence_chooser_dialog_show (GTK_WINDOW (window)); + dialog = empathy_status_preset_dialog_new (GTK_WINDOW (window)); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); } else if (type == ENTRY_TYPE_CUSTOM) { gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry), @@ -789,6 +799,13 @@ presence_chooser_finalize (GObject *object) G_OBJECT_CLASS (empathy_presence_chooser_parent_class)->finalize (object); } +/** + * empathy_presence_chooser_new: + * + * Creates a new #EmpathyPresenceChooser widget. + * + * Return value: A new #EmpathyPresenceChooser widget + */ GtkWidget * empathy_presence_chooser_new (void) { @@ -946,6 +963,13 @@ presence_chooser_flash_stop (EmpathyPresenceChooser *chooser, empathy_icon_name_for_presence (state)); } +/** + * empathy_presence_chooser_create_menu: + * + * Creates a new #GtkMenu allowing users to change their presence from a menu. + * + * Return value: a new #GtkMenu for changing presence in a menu. + */ GtkWidget * empathy_presence_chooser_create_menu (void) { @@ -1058,220 +1082,9 @@ static void presence_chooser_custom_activate_cb (GtkWidget *item, gpointer user_data) { - presence_chooser_dialog_show (NULL); -} - -static McPresence -presence_chooser_dialog_get_selected (CustomMessageDialog *dialog) -{ - GtkTreeModel *model; - GtkTreeIter iter; - McPresence presence = LAST_MC_PRESENCE; + GtkWidget *dialog; - model = gtk_combo_box_get_model (GTK_COMBO_BOX (dialog->combobox_status)); - if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (dialog->combobox_status), &iter)) { - gtk_tree_model_get (model, &iter, - COL_PRESENCE, &presence, - -1); - } - - return presence; + dialog = empathy_status_preset_dialog_new (NULL); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); } - -static void -presence_chooser_dialog_status_changed_cb (GtkWidget *widget, - CustomMessageDialog *dialog) -{ - GtkListStore *store; - GtkTreeIter iter; - McPresence presence = LAST_MC_PRESENCE; - GList *messages, *l; - - presence = presence_chooser_dialog_get_selected (dialog); - - store = gtk_list_store_new (1, G_TYPE_STRING); - messages = empathy_status_presets_get (presence, -1); - for (l = messages; l; l = l->next) { - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, 0, l->data, -1); - } - - gtk_entry_set_text (GTK_ENTRY (dialog->entry_message), - messages ? messages->data : ""); - - g_list_free (messages); - - gtk_combo_box_set_model (GTK_COMBO_BOX (dialog->comboboxentry_message), - GTK_TREE_MODEL (store)); - - g_object_unref (store); -} - -static void -presence_chooser_dialog_message_changed_cb (GtkWidget *widget, - CustomMessageDialog *dialog) -{ - McPresence presence; - GList *messages, *l; - const gchar *text; - gboolean found = FALSE; - - presence = presence_chooser_dialog_get_selected (dialog); - text = gtk_entry_get_text (GTK_ENTRY (dialog->entry_message)); - - messages = empathy_status_presets_get (presence, -1); - for (l = messages; l; l = l->next) { - if (!tp_strdiff (text, l->data)) { - found = TRUE; - break; - } - } - g_list_free (messages); - - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->checkbutton_save), - found); -} - -static void -presence_chooser_dialog_save_toggled_cb (GtkWidget *widget, - CustomMessageDialog *dialog) -{ - gboolean active; - McPresence state; - const gchar *text; - - active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->checkbutton_save)); - state = presence_chooser_dialog_get_selected (dialog); - text = gtk_entry_get_text (GTK_ENTRY (dialog->entry_message)); - - if (active) { - empathy_status_presets_set_last (state, text); - } else { - empathy_status_presets_remove (state, text); - } -} - -static void -presence_chooser_dialog_setup (CustomMessageDialog *dialog) -{ - GtkListStore *store; - GtkCellRenderer *renderer; - GtkTreeIter iter; - guint i; - - store = gtk_list_store_new (COL_COUNT, - G_TYPE_STRING, /* Icon name */ - G_TYPE_STRING, /* Label */ - MC_TYPE_PRESENCE); /* Presence */ - gtk_combo_box_set_model (GTK_COMBO_BOX (dialog->combobox_status), - GTK_TREE_MODEL (store)); - - renderer = gtk_cell_renderer_pixbuf_new (); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (dialog->combobox_status), renderer, FALSE); - gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (dialog->combobox_status), renderer, - "icon-name", COL_ICON, - 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 (dialog->combobox_status), renderer, TRUE); - gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (dialog->combobox_status), renderer, - "text", COL_LABEL, - NULL); - - for (i = 0; i < G_N_ELEMENTS (states); i += 2) { - if (!states[i+1]) { - continue; - } - - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, - COL_ICON, empathy_icon_name_for_presence (states[i]), - COL_LABEL, empathy_presence_get_default_message (states[i]), - COL_PRESENCE, states[i], - -1); - } - - gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->combobox_status), 0); -} - -static void -presence_chooser_dialog_response_cb (GtkWidget *widget, - gint response, - CustomMessageDialog *dialog) -{ - if (response == GTK_RESPONSE_APPLY) { - McPresence state; - const gchar *text; - - state = presence_chooser_dialog_get_selected (dialog); - text = gtk_entry_get_text (GTK_ENTRY (dialog->entry_message)); - - presence_chooser_set_state (state, text); - } - - gtk_widget_destroy (widget); -} - -static void -presence_chooser_dialog_destroy_cb (GtkWidget *widget, - CustomMessageDialog *dialog) -{ - - g_free (dialog); - message_dialog = NULL; -} - -static void -presence_chooser_dialog_show (GtkWindow *parent) -{ - GtkBuilder *gui; - gchar *filename; - - if (message_dialog) { - gtk_window_present (GTK_WINDOW (message_dialog->dialog)); - return; - } - - message_dialog = g_new0 (CustomMessageDialog, 1); - - filename = empathy_file_lookup ("empathy-presence-chooser.ui", - "libempathy-gtk"); - gui = empathy_builder_get_file (filename, - "custom_message_dialog", &message_dialog->dialog, - "checkbutton_save", &message_dialog->checkbutton_save, - "comboboxentry_message", &message_dialog->comboboxentry_message, - "combobox_status", &message_dialog->combobox_status, - NULL); - g_free (filename); - - empathy_builder_connect (gui, message_dialog, - "custom_message_dialog", "destroy", presence_chooser_dialog_destroy_cb, - "custom_message_dialog", "response", presence_chooser_dialog_response_cb, - "combobox_status", "changed", presence_chooser_dialog_status_changed_cb, - "checkbutton_save", "toggled", presence_chooser_dialog_save_toggled_cb, - NULL); - - g_object_unref (gui); - - /* Setup the message combobox */ - message_dialog->entry_message = GTK_BIN (message_dialog->comboboxentry_message)->child; - gtk_entry_set_activates_default (GTK_ENTRY (message_dialog->entry_message), TRUE); - gtk_entry_set_width_chars (GTK_ENTRY (message_dialog->entry_message), 25); - g_signal_connect (message_dialog->entry_message, "changed", - G_CALLBACK (presence_chooser_dialog_message_changed_cb), - message_dialog); - - presence_chooser_dialog_setup (message_dialog); - - gtk_combo_box_entry_set_text_column (GTK_COMBO_BOX_ENTRY (message_dialog->comboboxentry_message), 0); - - if (parent) { - gtk_window_set_transient_for ( - GTK_WINDOW (message_dialog->dialog), - parent); - } - - gtk_widget_show_all (message_dialog->dialog); -} - diff --git a/libempathy-gtk/empathy-presence-chooser.h b/libempathy-gtk/empathy-presence-chooser.h index 138e1dc7f..dab95f553 100644 --- a/libempathy-gtk/empathy-presence-chooser.h +++ b/libempathy-gtk/empathy-presence-chooser.h @@ -43,6 +43,8 @@ typedef struct _EmpathyPresenceChooserClass EmpathyPresenceChooserClass; struct _EmpathyPresenceChooser { GtkComboBoxEntry parent; + + /*<private>*/ gpointer priv; }; diff --git a/libempathy-gtk/empathy-presence-chooser.ui b/libempathy-gtk/empathy-presence-chooser.ui deleted file mode 100644 index 6e0a155d0..000000000 --- a/libempathy-gtk/empathy-presence-chooser.ui +++ /dev/null @@ -1,140 +0,0 @@ -<?xml version="1.0"?> -<interface> - <requires lib="gtk+" version="2.16"/> - <!-- interface-naming-policy toplevel-contextual --> - <object class="GtkDialog" id="custom_message_dialog"> - <property name="visible">True</property> - <property name="border_width">5</property> - <property name="title" translatable="yes">Custom message</property> - <property name="resizable">False</property> - <property name="type_hint">dialog</property> - <property name="has_separator">False</property> - <child internal-child="vbox"> - <object class="GtkVBox" id="dialog-vbox6"> - <property name="visible">True</property> - <child> - <object class="GtkTable" id="table1"> - <property name="visible">True</property> - <property name="border_width">5</property> - <property name="n_rows">3</property> - <property name="n_columns">2</property> - <property name="column_spacing">6</property> - <property name="row_spacing">6</property> - <child> - <object class="GtkComboBox" id="combobox_status"> - <property name="visible">True</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> - <object class="GtkComboBoxEntry" id="comboboxentry_message"> - <property name="visible">True</property> - </object> - <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="x_options">GTK_FILL</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> - <object class="GtkCheckButton" id="checkbutton_save"> - <property name="label" translatable="yes">Save message</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="use_underline">True</property> - <property name="draw_indicator">True</property> - </object> - <packing> - <property name="right_attach">2</property> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label472"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Message:</property> - </object> - <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label471"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Status:</property> - </object> - <packing> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - </object> - <packing> - <property name="position">1</property> - </packing> - </child> - <child internal-child="action_area"> - <object class="GtkHButtonBox" id="dialog-action_area6"> - <property name="visible">True</property> - <property name="layout_style">end</property> - <child> - <object class="GtkButton" id="closebutton1"> - <property name="label">gtk-cancel</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="can_default">True</property> - <property name="receives_default">False</property> - <property name="use_stock">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkButton" id="button1"> - <property name="label">gtk-apply</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="can_default">True</property> - <property name="receives_default">False</property> - <property name="use_stock">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="pack_type">end</property> - <property name="position">0</property> - </packing> - </child> - </object> - </child> - <action-widgets> - <action-widget response="-6">closebutton1</action-widget> - <action-widget response="-10">button1</action-widget> - </action-widgets> - </object> -</interface> diff --git a/libempathy-gtk/empathy-profile-chooser.c b/libempathy-gtk/empathy-profile-chooser.c index fd68dd8b0..10eb3791a 100644 --- a/libempathy-gtk/empathy-profile-chooser.c +++ b/libempathy-gtk/empathy-profile-chooser.c @@ -30,6 +30,16 @@ #include "empathy-profile-chooser.h" #include "empathy-ui-utils.h" +/** + * SECTION:empathy-profile-chooser + * @title: EmpathyProfileChooser + * @short_description: A widget used to choose from a list of profiles + * @include: libempathy-gtk/empathy-account-chooser.h + * + * #EmpathyProfileChooser is a widget which provides a chooser of available + * profiles. + */ + enum { COL_ICON, COL_LABEL, @@ -37,8 +47,17 @@ enum { COL_COUNT }; +/** + * empathy_profile_chooser_dup_selected: + * @widget: an #EmpathyProfileChooser + * + * Returns a new reference to the selected #McProfile in @widget. The returned + * #McProfile should be unrefed with g_object_unref() when finished with. + * + * Return value: a new reference to the selected #McProfile + */ McProfile* -empathy_profile_chooser_get_selected (GtkWidget *widget) +empathy_profile_chooser_dup_selected (GtkWidget *widget) { GtkTreeModel *model; GtkTreeIter iter; @@ -54,6 +73,14 @@ empathy_profile_chooser_get_selected (GtkWidget *widget) return profile; } +/** + * empathy_profile_chooser_n_profiles: + * @widget: an #EmpathyProfileChooser + * + * Returns the number of profiles in @widget. + * + * Return value: the number of profiles in @widget + */ gint empathy_profile_chooser_n_profiles (GtkWidget *widget) { @@ -115,6 +142,13 @@ profile_chooser_sort_func (GtkTreeModel *model, return cmp; } +/** + * empathy_profile_chooser_new: + * + * Creates a new #EmpathyProfileChooser widget. + * + * Return value: a new #EmpathyProfileChooser widget + */ GtkWidget * empathy_profile_chooser_new (void) { diff --git a/libempathy-gtk/empathy-profile-chooser.h b/libempathy-gtk/empathy-profile-chooser.h index 8cdc33d67..74c761cc4 100644 --- a/libempathy-gtk/empathy-profile-chooser.h +++ b/libempathy-gtk/empathy-profile-chooser.h @@ -27,7 +27,7 @@ G_BEGIN_DECLS GtkWidget * empathy_profile_chooser_new (void); -McProfile * empathy_profile_chooser_get_selected (GtkWidget *widget); +McProfile * empathy_profile_chooser_dup_selected (GtkWidget *widget); gint empathy_profile_chooser_n_profiles (GtkWidget *widget); G_END_DECLS diff --git a/libempathy-gtk/empathy-spell-dialog.c b/libempathy-gtk/empathy-spell-dialog.c deleted file mode 100644 index 9ce80eebb..000000000 --- a/libempathy-gtk/empathy-spell-dialog.c +++ /dev/null @@ -1,264 +0,0 @@ -/* -*- 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. - */ - -#include "config.h" - -#include <string.h> - -#include <glib/gi18n-lib.h> -#include <gtk/gtk.h> - -#include <libempathy/empathy-utils.h> - -#include "empathy-chat.h" -#include "empathy-spell.h" -#include "empathy-spell-dialog.h" -#include "empathy-ui-utils.h" - -typedef struct { - GtkWidget *window; - GtkWidget *button_replace; - GtkWidget *label_word; - GtkWidget *treeview_words; - - EmpathyChat *chat; - - gchar *word; - GtkTextIter start; - GtkTextIter end; -} EmpathySpellDialog; - -enum { - COL_SPELL_WORD, - COL_SPELL_COUNT -}; - -static void spell_dialog_model_populate_columns (EmpathySpellDialog *dialog); -static void spell_dialog_model_populate_suggestions (EmpathySpellDialog *dialog); -static void spell_dialog_model_row_activated_cb (GtkTreeView *tree_view, - GtkTreePath *path, - GtkTreeViewColumn *column, - EmpathySpellDialog *dialog); -static void spell_dialog_model_selection_changed_cb (GtkTreeSelection *treeselection, - EmpathySpellDialog *dialog); -static void spell_dialog_model_setup (EmpathySpellDialog *dialog); -static void spell_dialog_response_cb (GtkWidget *widget, - gint response, - EmpathySpellDialog *dialog); -static void spell_dialog_destroy_cb (GtkWidget *widget, - EmpathySpellDialog *dialog); - -static void -spell_dialog_model_populate_columns (EmpathySpellDialog *dialog) -{ - GtkTreeModel *model; - GtkTreeViewColumn *column; - GtkCellRenderer *renderer; - guint col_offset; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview_words)); - - renderer = gtk_cell_renderer_text_new (); - col_offset = gtk_tree_view_insert_column_with_attributes ( - GTK_TREE_VIEW (dialog->treeview_words), - -1, _("Word"), - renderer, - "text", COL_SPELL_WORD, - NULL); - - g_object_set_data (G_OBJECT (renderer), - "column", GINT_TO_POINTER (COL_SPELL_WORD)); - - column = gtk_tree_view_get_column (GTK_TREE_VIEW (dialog->treeview_words), col_offset - 1); - gtk_tree_view_column_set_sort_column_id (column, COL_SPELL_WORD); - gtk_tree_view_column_set_resizable (column, FALSE); - gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE); -} - -static void -spell_dialog_model_populate_suggestions (EmpathySpellDialog *dialog) -{ - GtkTreeModel *model; - GtkListStore *store; - GList *suggestions, *l; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview_words)); - store = GTK_LIST_STORE (model); - - suggestions = empathy_spell_get_suggestions (dialog->word); - for (l = suggestions; l; l=l->next) { - GtkTreeIter iter; - gchar *word; - - word = l->data; - - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, - COL_SPELL_WORD, word, - -1); - } - - empathy_spell_free_suggestions (suggestions); -} - -static void -spell_dialog_model_row_activated_cb (GtkTreeView *tree_view, - GtkTreePath *path, - GtkTreeViewColumn *column, - EmpathySpellDialog *dialog) -{ - spell_dialog_response_cb (dialog->window, GTK_RESPONSE_OK, dialog); -} - -static void -spell_dialog_model_selection_changed_cb (GtkTreeSelection *treeselection, - EmpathySpellDialog *dialog) -{ - gint count; - - count = gtk_tree_selection_count_selected_rows (treeselection); - gtk_widget_set_sensitive (dialog->button_replace, (count == 1)); -} - -static void -spell_dialog_model_setup (EmpathySpellDialog *dialog) -{ - GtkTreeView *view; - GtkListStore *store; - GtkTreeSelection *selection; - - view = GTK_TREE_VIEW (dialog->treeview_words); - - g_signal_connect (view, "row-activated", - G_CALLBACK (spell_dialog_model_row_activated_cb), - dialog); - - store = gtk_list_store_new (COL_SPELL_COUNT, - G_TYPE_STRING); /* word */ - - gtk_tree_view_set_model (view, GTK_TREE_MODEL (store)); - - selection = gtk_tree_view_get_selection (view); - gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); - - g_signal_connect (selection, "changed", - G_CALLBACK (spell_dialog_model_selection_changed_cb), - dialog); - - spell_dialog_model_populate_columns (dialog); - spell_dialog_model_populate_suggestions (dialog); - - g_object_unref (store); -} - -static void -spell_dialog_destroy_cb (GtkWidget *widget, - EmpathySpellDialog *dialog) -{ - g_object_unref (dialog->chat); - g_free (dialog->word); - - g_free (dialog); -} - -static void -spell_dialog_response_cb (GtkWidget *widget, - gint response, - EmpathySpellDialog *dialog) -{ - if (response == GTK_RESPONSE_OK) { - GtkTreeView *view; - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkTreeIter iter; - - gchar *new_word; - - view = GTK_TREE_VIEW (dialog->treeview_words); - selection = gtk_tree_view_get_selection (view); - - if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { - return; - } - - gtk_tree_model_get (model, &iter, COL_SPELL_WORD, &new_word, -1); - - empathy_chat_correct_word (dialog->chat, - &dialog->start, - &dialog->end, - new_word); - - g_free (new_word); - } - - gtk_widget_destroy (dialog->window); -} - -void -empathy_spell_dialog_show (EmpathyChat *chat, - GtkTextIter *start, - GtkTextIter *end, - const gchar *word) -{ - EmpathySpellDialog *dialog; - GtkBuilder *gui; - gchar *str; - gchar *filename; - - g_return_if_fail (chat != NULL); - g_return_if_fail (word != NULL); - - dialog = g_new0 (EmpathySpellDialog, 1); - - dialog->chat = g_object_ref (chat); - - dialog->word = g_strdup (word); - - dialog->start = *start; - dialog->end = *end; - - filename = empathy_file_lookup ("empathy-spell-dialog.ui", - "libempathy-gtk"); - gui = empathy_builder_get_file (filename, - "spell_dialog", &dialog->window, - "button_replace", &dialog->button_replace, - "label_word", &dialog->label_word, - "treeview_words", &dialog->treeview_words, - NULL); - g_free (filename); - - empathy_builder_connect (gui, dialog, - "spell_dialog", "response", spell_dialog_response_cb, - "spell_dialog", "destroy", spell_dialog_destroy_cb, - NULL); - - g_object_unref (gui); - - str = g_markup_printf_escaped ("%s:\n<b>%s</b>", - _("Suggestions for the word"), - word); - - gtk_label_set_markup (GTK_LABEL (dialog->label_word), str); - g_free (str); - - spell_dialog_model_setup (dialog); - - gtk_widget_show (dialog->window); -} diff --git a/libempathy-gtk/empathy-spell-dialog.h b/libempathy-gtk/empathy-spell-dialog.h deleted file mode 100644 index ce0218812..000000000 --- a/libempathy-gtk/empathy-spell-dialog.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- 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: Martyn Russell <martyn@imendio.com> - * Richard Hult <richard@imendio.com> - */ - -#ifndef __EMPATHY_SPELL_DIALOG_H__ -#define __EMPATHY_SPELL_DIALOG_H__ - -#include <gtk/gtktextiter.h> -#include "empathy-chat.h" - -G_BEGIN_DECLS - -void empathy_spell_dialog_show (EmpathyChat *chat, - GtkTextIter *start, - GtkTextIter *end, - const gchar *word); - -G_END_DECLS - -#endif /* __EMPATHY_SPELL_DIALOG_H__ */ diff --git a/libempathy-gtk/empathy-spell-dialog.ui b/libempathy-gtk/empathy-spell-dialog.ui deleted file mode 100644 index 382346c1a..000000000 --- a/libempathy-gtk/empathy-spell-dialog.ui +++ /dev/null @@ -1,131 +0,0 @@ -<?xml version="1.0"?> -<!--*- mode: xml -*--> -<interface> - <object class="GtkDialog" id="spell_dialog"> - <property name="border_width">5</property> - <property name="title" translatable="yes">Spell Checker</property> - <property name="modal">True</property> - <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> - <property name="default_width">275</property> - <property name="default_height">225</property> - <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> - <property name="has_separator">False</property> - <child internal-child="vbox"> - <object class="GtkVBox" id="dialog-vbox7"> - <property name="visible">True</property> - <property name="spacing">2</property> - <child> - <object class="GtkVBox" id="vbox128"> - <property name="visible">True</property> - <property name="border_width">5</property> - <property name="spacing">6</property> - <child> - <object class="GtkLabel" id="label_word"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Suggestions for the word:</property> - <property name="use_markup">True</property> - <property name="wrap">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - <child> - <object class="GtkScrolledWindow" id="scrolledwindow9"> - <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> - <child> - <object class="GtkTreeView" id="treeview_words"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="headers_visible">False</property> - </object> - </child> - </object> - <packing> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="position">1</property> - </packing> - </child> - <child internal-child="action_area"> - <object class="GtkHButtonBox" id="dialog-action_area7"> - <property name="visible">True</property> - <property name="layout_style">GTK_BUTTONBOX_END</property> - <child> - <object class="GtkButton" id="button_cancel"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="can_default">True</property> - <property name="label">gtk-cancel</property> - <property name="use_stock">True</property> - </object> - </child> - <child> - <object class="GtkButton" id="button_replace"> - <property name="visible">True</property> - <property name="sensitive">False</property> - <property name="can_focus">True</property> - <property name="can_default">True</property> - <child> - <object class="GtkAlignment" id="alignment6"> - <property name="visible">True</property> - <property name="xscale">0</property> - <property name="yscale">0</property> - <child> - <object class="GtkHBox" id="hbox135"> - <property name="visible">True</property> - <property name="spacing">2</property> - <child> - <object class="GtkImage" id="image245"> - <property name="visible">True</property> - <property name="stock">gtk-convert</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label594"> - <property name="visible">True</property> - <property name="label">_Replace</property> - <property name="use_underline">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - </object> - </child> - </object> - <packing> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="pack_type">GTK_PACK_END</property> - </packing> - </child> - </object> - </child> - <action-widgets> - <action-widget response="-6">button_cancel</action-widget> - <action-widget response="-5">button_replace</action-widget> - </action-widgets> - </object> -</interface> diff --git a/libempathy-gtk/empathy-status-preset-dialog.c b/libempathy-gtk/empathy-status-preset-dialog.c new file mode 100644 index 000000000..734ac356a --- /dev/null +++ b/libempathy-gtk/empathy-status-preset-dialog.c @@ -0,0 +1,549 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * empathy-status-preset-dialog.c + * + * EmpathyStatusPresetDialog - a dialog for adding and removing preset status + * messages. + * + * Copyright (C) 2009 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: Davyd Madeley <davyd.madeley@collabora.co.uk> + */ +/** + * SECTION:empathy-status-preset-dialog + * @title: EmpathyStatusPresetDialog + * @short_description: a dialog for editing the saved status messages + * @include: libempathy-gtk/empathy-status-preset-dialog.h + * + * #EmpathyStatusPresetDialog is a dialog allowing the user to add/remove/edit + * their saved status messages. + */ + +#include "config.h" + +#include <glib/gi18n-lib.h> +#include <gtk/gtk.h> + +#include <libmissioncontrol/mc-enum-types.h> + +#include <libempathy/empathy-utils.h> +#include <libempathy/empathy-status-presets.h> + +#define DEBUG_FLAG EMPATHY_DEBUG_OTHER +#include <libempathy/empathy-debug.h> + +#include "empathy-ui-utils.h" +#include "empathy-status-preset-dialog.h" + +#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyStatusPresetDialog) + +G_DEFINE_TYPE (EmpathyStatusPresetDialog, empathy_status_preset_dialog, GTK_TYPE_DIALOG); + +static McPresence states[] = { + MC_PRESENCE_AVAILABLE, + MC_PRESENCE_DO_NOT_DISTURB, + MC_PRESENCE_AWAY +}; + +typedef struct _EmpathyStatusPresetDialogPriv EmpathyStatusPresetDialogPriv; +struct _EmpathyStatusPresetDialogPriv +{ + /* block status_preset_dialog_add_combo_changed() when > 0 */ + int block_add_combo_changed; + + GtkWidget *presets_treeview; + GtkWidget *add_combobox; + GtkWidget *add_button; + + GtkTreeIter selected_iter; + gboolean add_combo_changed; + char *saved_status; +}; + +enum +{ + PRESETS_STORE_STATE, + PRESETS_STORE_ICON_NAME, + PRESETS_STORE_STATUS, + PRESETS_STORE_N_COLS +}; + +enum +{ + ADD_COMBO_STATE, + ADD_COMBO_ICON_NAME, + ADD_COMBO_STATUS, + ADD_COMBO_DEFAULT_TEXT, + ADD_COMBO_N_COLS +}; + +static void +empathy_status_preset_dialog_finalize (GObject *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + + g_free (priv->saved_status); + + G_OBJECT_CLASS (empathy_status_preset_dialog_parent_class)->finalize (self); +} + +static void +empathy_status_preset_dialog_class_init (EmpathyStatusPresetDialogClass *class) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (class); + gobject_class->finalize = empathy_status_preset_dialog_finalize; + + g_type_class_add_private (gobject_class, + sizeof (EmpathyStatusPresetDialogPriv)); +} + +static void +status_preset_dialog_presets_update (EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + GtkListStore *store; + int i; + + store = GTK_LIST_STORE (gtk_tree_view_get_model ( + GTK_TREE_VIEW (priv->presets_treeview))); + + gtk_list_store_clear (store); + + for (i = 0; i < G_N_ELEMENTS (states); i++) { + GList *presets, *l; + const char *icon_name; + + icon_name = empathy_icon_name_for_presence (states[i]); + presets = empathy_status_presets_get (states[i], -1); + presets = g_list_sort (presets, (GCompareFunc) g_utf8_collate); + + for (l = presets; l; l = l->next) { + char *preset = (char *) l->data; + + gtk_list_store_insert_with_values (store, + NULL, -1, + PRESETS_STORE_STATE, states[i], + PRESETS_STORE_ICON_NAME, icon_name, + PRESETS_STORE_STATUS, preset, + -1); + } + + g_list_free (presets); + } +} + +static void +status_preset_add_combo_reset (EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->add_combobox), + &priv->selected_iter); +} + +static void +status_preset_dialog_setup_add_combobox (EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + GtkWidget *combobox = priv->add_combobox; + GtkListStore *store; + GtkCellRenderer *renderer; + int i; + + store = gtk_list_store_new (ADD_COMBO_N_COLS, + MC_TYPE_PRESENCE, /* ADD_COMBO_STATE */ + G_TYPE_STRING, /* ADD_COMBO_ICON_NAME */ + G_TYPE_STRING, /* ADD_COMBO_STATUS */ + G_TYPE_STRING); /* ADD_COMBO_DEFAULT_TEXT */ + + gtk_combo_box_set_model (GTK_COMBO_BOX (combobox), + GTK_TREE_MODEL (store)); + g_object_unref (store); + + gtk_combo_box_entry_set_text_column (GTK_COMBO_BOX_ENTRY (combobox), + ADD_COMBO_DEFAULT_TEXT); + + for (i = 0; i < G_N_ELEMENTS (states); i++) { + gtk_list_store_insert_with_values (store, NULL, -1, + ADD_COMBO_STATE, states[i], + ADD_COMBO_ICON_NAME, empathy_icon_name_for_presence (states[i]), + ADD_COMBO_STATUS, empathy_presence_get_default_message (states[i]), + ADD_COMBO_DEFAULT_TEXT, "", + -1); + } + + gtk_cell_layout_clear (GTK_CELL_LAYOUT (combobox)); + + renderer = gtk_cell_renderer_pixbuf_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox), renderer, FALSE); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combobox), renderer, + "icon-name", ADD_COMBO_ICON_NAME); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox), renderer, TRUE); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combobox), renderer, + "text", ADD_COMBO_STATUS); + g_object_set (renderer, + "style", PANGO_STYLE_ITALIC, + "foreground", "Gray", /* FIXME - theme */ + NULL); + + gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), 0); +} + +static void +status_preset_dialog_status_edited (GtkCellRendererText *renderer, + char *path_str, + char *new_status, + EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + GtkTreeModel *model; + GtkTreePath *path; + GtkTreeIter iter; + McPresence state; + char *old_status; + gboolean valid; + + if (strlen (new_status) == 0) { + /* status is empty, ignore */ + return; + } + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->presets_treeview)); + path = gtk_tree_path_new_from_string (path_str); + valid = gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_path_free (path); + + if (!valid) return; + + gtk_tree_model_get (model, &iter, + PRESETS_STORE_STATE, &state, + PRESETS_STORE_STATUS, &old_status, + -1); + + if (!strcmp (old_status, new_status)) { + /* statuses are the same */ + g_free (old_status); + return; + } + + DEBUG ("EDITED STATUS (%s) -> (%s)\n", old_status, new_status); + + empathy_status_presets_remove (state, old_status); + empathy_status_presets_set_last (state, new_status); + + g_free (old_status); + + status_preset_dialog_presets_update (self); +} + +static void +status_preset_dialog_setup_presets_treeview (EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + GtkWidget *treeview = priv->presets_treeview; + GtkListStore *store; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + + store = gtk_list_store_new (PRESETS_STORE_N_COLS, + MC_TYPE_PRESENCE, /* PRESETS_STORE_STATE */ + G_TYPE_STRING, /* PRESETS_STORE_ICON_NAME */ + G_TYPE_STRING); /* PRESETS_STORE_STATUS */ + + gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), + GTK_TREE_MODEL (store)); + g_object_unref (store); + + status_preset_dialog_presets_update (self); + + column = gtk_tree_view_column_new (); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + + renderer = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_start (column, renderer, FALSE); + gtk_tree_view_column_add_attribute (column, renderer, + "icon-name", PRESETS_STORE_ICON_NAME); + + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + gtk_tree_view_column_add_attribute (column, renderer, + "text", PRESETS_STORE_STATUS); + g_object_set (renderer, + "editable", TRUE, + NULL); + g_signal_connect (renderer, "edited", + G_CALLBACK (status_preset_dialog_status_edited), self); +} + +static void +status_preset_dialog_preset_selection_changed (GtkTreeSelection *selection, + GtkWidget *remove_button) +{ + /* update the sensitivity of the Remove button */ + gtk_widget_set_sensitive (remove_button, + gtk_tree_selection_get_selected (selection, NULL, NULL)); +} + +static void +status_preset_dialog_preset_remove (GtkButton *button, + EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + McPresence state; + char *status; + + selection = gtk_tree_view_get_selection ( + GTK_TREE_VIEW (priv->presets_treeview)); + + g_return_if_fail (gtk_tree_selection_get_selected (selection, + &model, &iter)); + + gtk_tree_model_get (model, &iter, + PRESETS_STORE_STATE, &state, + PRESETS_STORE_STATUS, &status, + -1); + + DEBUG ("REMOVE PRESET (%i, %s)\n", state, status); + empathy_status_presets_remove (state, status); + + g_free (status); + + status_preset_dialog_presets_update (self); +} + +static void +status_preset_dialog_set_add_combo_changed (EmpathyStatusPresetDialog *self, + gboolean state, + gboolean reset_text) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + GtkWidget *entry; + + entry = gtk_bin_get_child (GTK_BIN (priv->add_combobox)); + + priv->add_combo_changed = state; + gtk_widget_set_sensitive (priv->add_button, state); + + if (state) { + gtk_widget_modify_text (entry, GTK_STATE_NORMAL, NULL); + } else { + GdkColor colour; + + gdk_color_parse ("Gray", &colour); /* FIXME - theme */ + gtk_widget_modify_text (entry, GTK_STATE_NORMAL, &colour); + + if (reset_text) { + priv->block_add_combo_changed++; + gtk_entry_set_text (GTK_ENTRY (entry), + _("Enter Custom Message")); + priv->block_add_combo_changed--; + } + } +} + +static void +status_preset_dialog_add_combo_changed (GtkComboBox *combo, + EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + GtkWidget *entry; + GtkTreeModel *model; + GtkTreeIter iter; + + if (priv->block_add_combo_changed) return; + + model = gtk_combo_box_get_model (combo); + entry = gtk_bin_get_child (GTK_BIN (combo)); + + if (gtk_combo_box_get_active_iter (combo, &iter)) { + char *icon_name; + + priv->selected_iter = iter; + gtk_tree_model_get (model, &iter, + PRESETS_STORE_ICON_NAME, &icon_name, + -1); + + gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry), + GTK_ENTRY_ICON_PRIMARY, + icon_name); + + g_free (icon_name); + + status_preset_dialog_set_add_combo_changed (self, FALSE, TRUE); + if (priv->saved_status && strlen (priv->saved_status) > 0) { + gtk_entry_set_text (GTK_ENTRY (entry), + priv->saved_status); + } + } else { + g_free (priv->saved_status); + priv->saved_status = g_strdup ( + gtk_entry_get_text (GTK_ENTRY (entry))); + + status_preset_dialog_set_add_combo_changed (self, + strlen (priv->saved_status) > 0, FALSE); + } +} + +static void +status_preset_dialog_add_preset (GtkWidget *widget, + EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + GtkTreeModel *model; + GtkWidget *entry; + McPresence state; + const char *status; + + g_return_if_fail (priv->add_combo_changed); + + model = gtk_combo_box_get_model (GTK_COMBO_BOX (priv->add_combobox)); + entry = gtk_bin_get_child (GTK_BIN (priv->add_combobox)); + + status = gtk_entry_get_text (GTK_ENTRY (entry)); + gtk_tree_model_get (model, &priv->selected_iter, + PRESETS_STORE_STATE, &state, + -1); + + DEBUG ("ADD PRESET (%i, %s)\n", state, status); + empathy_status_presets_set_last (state, status); + + status_preset_dialog_presets_update (self); + status_preset_add_combo_reset (self); +} + +static gboolean +status_preset_dialog_add_combo_press_event (GtkWidget *widget, + GdkEventButton *event, + EmpathyStatusPresetDialog *self) +{ + if (!GTK_WIDGET_HAS_FOCUS (widget)) { + /* if the widget isn't focused, focus it and select the text */ + gtk_widget_grab_focus (widget); + gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1); + + return TRUE; + } + + return FALSE; +} + +static gboolean +status_preset_dialog_add_combo_focus_out (GtkWidget *widget, + GdkEventFocus *event, + EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + const char *status; + + gtk_editable_set_position (GTK_EDITABLE (widget), 0); + + status = gtk_entry_get_text (GTK_ENTRY (widget)); + status_preset_dialog_set_add_combo_changed (self, + priv->add_combo_changed && strlen (status) > 0, + TRUE); + + return FALSE; +} + +static void +empathy_status_preset_dialog_init (EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = self->priv = + G_TYPE_INSTANCE_GET_PRIVATE (self, + EMPATHY_TYPE_STATUS_PRESET_DIALOG, + EmpathyStatusPresetDialogPriv); + GtkBuilder *gui; + GtkWidget *toplevel_vbox, *remove_button, *entry; + char *filename; + + gtk_window_set_title (GTK_WINDOW (self), + _("Edit Custom Messages")); + gtk_dialog_set_has_separator (GTK_DIALOG (self), FALSE); + gtk_dialog_add_button (GTK_DIALOG (self), + GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE); + + filename = empathy_file_lookup ("empathy-status-preset-dialog.ui", + "libempathy-gtk"); + gui = empathy_builder_get_file (filename, + "toplevel-vbox", &toplevel_vbox, + "presets-treeview", &priv->presets_treeview, + "remove-button", &remove_button, + "add-combobox", &priv->add_combobox, + "add-button", &priv->add_button, + NULL); + g_free (filename); + + g_signal_connect (gtk_tree_view_get_selection ( + GTK_TREE_VIEW (priv->presets_treeview)), + "changed", + G_CALLBACK (status_preset_dialog_preset_selection_changed), + remove_button); + + entry = gtk_bin_get_child (GTK_BIN (priv->add_combobox)); + g_signal_connect (entry, "activate", + G_CALLBACK (status_preset_dialog_add_preset), self); + g_signal_connect (entry, "button-press-event", + G_CALLBACK (status_preset_dialog_add_combo_press_event), + self); + g_signal_connect (entry, "focus-out-event", + G_CALLBACK (status_preset_dialog_add_combo_focus_out), + self); + + empathy_builder_connect (gui, self, + "remove-button", "clicked", status_preset_dialog_preset_remove, + "add-combobox", "changed", status_preset_dialog_add_combo_changed, + "add-button", "clicked", status_preset_dialog_add_preset, + NULL); + + status_preset_dialog_setup_presets_treeview (self); + status_preset_dialog_setup_add_combobox (self); + + gtk_box_pack_start(GTK_BOX (GTK_DIALOG (self)->vbox), toplevel_vbox, + TRUE, TRUE, 0); + + g_object_unref (gui); +} + +/** + * empathy_status_preset_dialog_new: + * @parent: the parent window of this dialog (or NULL) + * + * Creates a new #EmpathyStatusPresetDialog that allows the user to + * add/remove/edit their saved status messages. + * + * Returns: the newly constructed dialog. + */ +GtkWidget * +empathy_status_preset_dialog_new (GtkWindow *parent) +{ + GtkWidget *self = g_object_new (EMPATHY_TYPE_STATUS_PRESET_DIALOG, + NULL); + + if (parent) { + gtk_window_set_transient_for (GTK_WINDOW (self), parent); + } + + return self; +} diff --git a/libempathy-gtk/empathy-status-preset-dialog.h b/libempathy-gtk/empathy-status-preset-dialog.h new file mode 100644 index 000000000..e53c3d8ad --- /dev/null +++ b/libempathy-gtk/empathy-status-preset-dialog.h @@ -0,0 +1,63 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * empathy-status-preset-dialog.c + * + * EmpathyStatusPresetDialog - a dialog for adding and removing preset status + * messages. + * + * Copyright (C) 2009 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: Davyd Madeley <davyd.madeley@collabora.co.uk> + */ + +#ifndef __EMPATHY_STATUS_PRESET_DIALOG_H__ +#define __EMPATHY_STATUS_PRESET_DIALOG_H__ + +#include <glib.h> + +G_BEGIN_DECLS + +#define EMPATHY_TYPE_STATUS_PRESET_DIALOG (empathy_status_preset_dialog_get_type ()) +#define EMPATHY_STATUS_PRESET_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EMPATHY_TYPE_STATUS_PRESET_DIALOG, EmpathyStatusPresetDialog)) +#define EMPATHY_STATUS_PRESET_DIALOG_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), EMPATHY_TYPE_STATUS_PRESET_DIALOG, EmpathyStatusPresetDialogClass)) +#define EMPATHY_IS_STATUS_PRESET_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EMPATHY_TYPE_STATUS_PRESET_DIALOG)) +#define EMPATHY_IS_STATUS_PRESET_DIALOG_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), EMPATHY_TYPE_STATUS_PRESET_DIALOG)) +#define EMPATHY_STATUS_PRESET_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EMPATHY_TYPE_STATUS_PRESET_DIALOG, EmpathyStatusPresetDialogClass)) + +typedef struct _EmpathyStatusPresetDialog EmpathyStatusPresetDialog; +typedef struct _EmpathyStatusPresetDialogClass EmpathyStatusPresetDialogClass; + +struct _EmpathyStatusPresetDialog +{ + GtkDialog parent; + + /*< private >*/ + gpointer priv; +}; + +struct _EmpathyStatusPresetDialogClass +{ + GtkDialogClass parent_class; +}; + +GType empathy_status_preset_dialog_get_type (void); +GtkWidget *empathy_status_preset_dialog_new (GtkWindow *parent); + +G_END_DECLS + +#endif diff --git a/libempathy-gtk/empathy-status-preset-dialog.ui b/libempathy-gtk/empathy-status-preset-dialog.ui new file mode 100644 index 000000000..ead8ab85d --- /dev/null +++ b/libempathy-gtk/empathy-status-preset-dialog.ui @@ -0,0 +1,116 @@ +<?xml version="1.0"?> +<interface> + <requires lib="gtk+" version="2.16"/> + <!-- interface-naming-policy project-wide --> + <object class="GtkVBox" id="toplevel-vbox"> + <property name="visible">True</property> + <property name="border_width">6</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel" id="label2"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Saved Presets</property> + <property name="mnemonic_widget">add-combobox</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> + </object> + <packing> + <property name="expand">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow" id="scrolledwindow1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">never</property> + <property name="shadow_type">etched-in</property> + <child> + <object class="GtkTreeView" id="presets-treeview"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="headers_visible">False</property> + </object> + </child> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkHButtonBox" id="hbuttonbox1"> + <property name="visible">True</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="remove-button"> + <property name="label" translatable="yes">gtk-remove</property> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Add _New Preset</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">add-combobox</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> + </object> + <packing> + <property name="expand">False</property> + <property name="position">3</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="hbox1"> + <property name="visible">True</property> + <property name="spacing">3</property> + <child> + <object class="GtkComboBoxEntry" id="add-combobox"> + <property name="visible">True</property> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="add-button"> + <property name="label" translatable="yes">gtk-add</property> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">4</property> + </packing> + </child> + </object> +</interface> diff --git a/libempathy-gtk/empathy-theme-boxes.c b/libempathy-gtk/empathy-theme-boxes.c index 0561ecac0..5b435f1d5 100644 --- a/libempathy-gtk/empathy-theme-boxes.c +++ b/libempathy-gtk/empathy-theme-boxes.c @@ -208,9 +208,9 @@ theme_boxes_maybe_append_header (EmpathyThemeBoxes *theme, DEBUG ("Maybe add fancy header"); /* Only insert a header if the previously inserted block is not the same - * as this one. This catches all the different cases: + * as this one. */ - if (last_contact && empathy_contact_equal (last_contact, contact)) { + if (last_contact == contact) { return; } diff --git a/libempathy-gtk/empathy-ui-utils.c b/libempathy-gtk/empathy-ui-utils.c index aa3492899..9a249e65b 100644 --- a/libempathy-gtk/empathy-ui-utils.c +++ b/libempathy-gtk/empathy-ui-utils.c @@ -102,7 +102,7 @@ builder_get_file_valist (const gchar *filename, gui = gtk_builder_new (); if (!gtk_builder_add_from_file (gui, filename, &error)) { - DEBUG ("Error: %s", error->message); + g_critical ("GtkBuilder Error: %s", error->message); g_clear_error (&error); g_object_unref (gui); return NULL; |