ekiga r6016 - in trunk: . src/gui



Author: dsandras
Date: Sun Mar  2 11:03:36 2008
New Revision: 6016
URL: http://svn.gnome.org/viewvc/ekiga?rev=6016&view=rev

Log:
Added widget allowing to define custom status messages, and to delete
them. This updates the GmConf keys that are being watched by the
GmConf PersonalDetails component. 


Added:
   trunk/src/gui/statusmenu.cpp
   trunk/src/gui/statusmenu.h
Modified:
   trunk/ChangeLog

Added: trunk/src/gui/statusmenu.cpp
==============================================================================
--- (empty file)
+++ trunk/src/gui/statusmenu.cpp	Sun Mar  2 11:03:36 2008
@@ -0,0 +1,934 @@
+
+/* Ekiga -- A VoIP and Video-Conferencing application
+ * Copyright (C) 2000-2008 Damien Sandras
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ *
+ * Ekiga is licensed under the GPL license and as a special exception,
+ * you have permission to link or otherwise combine this program with the
+ * programs OPAL, OpenH323 and PWLIB, and distribute the combination,
+ * without applying the requirements of the GNU GPL to the OPAL, OpenH323
+ * and PWLIB programs, as long as you do follow the requirements of the
+ * GNU GPL for all the rest of the software thus combined.
+ */
+
+
+/*
+ *                         statusmenu.h  -  description
+ *                         -------------------------------
+ *   begin                : Mon Jan 28 2008
+ *   copyright            : (C) 2000-2008 by Damien Sandras 
+ *   description          : Contains a StatusMenu
+ *
+ */
+
+#include "config.h"
+#include "statusmenu.h"
+
+#include "gmconf.h"
+#include "gmstockicons.h"
+
+#include "common.h"
+
+
+struct _StatusMenuPrivate
+{
+  GtkListStore *list_store; // List store storing the menu
+  GtkWindow    *parent;     // Parent window
+};
+
+enum Columns
+{
+  COL_ICON,          // The status icon
+  COL_MESSAGE,       // The status message (if any)
+  COL_MESSAGE_TYPE,  // The status message type
+  COL_SEPARATOR,     // A separator
+  NUM_COLUMNS
+};
+
+enum MessageType
+{
+  TYPE_ONLINE,             // Generic online message
+  TYPE_AWAY,               // Generic away message
+  TYPE_DND,                // Generic Do Not Disturb message
+  NUM_STATUS_TYPES,
+  TYPE_CUSTOM_ONLINE,      // Custom online message
+  TYPE_CUSTOM_AWAY,        // Custom away message
+  TYPE_CUSTOM_DND,         // Custom DND message
+  NUM_STATUS_CUSTOM_TYPES,
+  TYPE_CUSTOM_ONLINE_NEW,  // Add new custom online message
+  TYPE_CUSTOM_AWAY_NEW,    // Add new custom away message
+  TYPE_CUSTOM_DND_NEW,     // Add new custom dnd message
+  TYPE_CLEAR               // Clear custom message(s)
+};
+
+const char* statuses[] = 
+{ 
+  _("Online"), 
+  _("Away"), 
+  _("Do Not Disturb") 
+};
+
+const char* status_types_names[] = 
+{ 
+  "online",
+  "away",
+  "dnd"
+};
+
+const char* status_types_keys[] = 
+{ 
+  PERSONAL_DATA_KEY "online_custom_status",
+  PERSONAL_DATA_KEY "away_custom_status",
+  PERSONAL_DATA_KEY "dnd_custom_status"
+};
+
+const char* stock_status[] = 
+{ 
+  GM_STOCK_STATUS_ONLINE,
+  GM_STOCK_STATUS_AWAY,
+  GM_STOCK_STATUS_DND
+};
+
+
+/**
+ * Callbacks
+ */
+
+/** Return true if the row is a separator.
+ *
+ * @param model is a pointer to the GtkTreeModel
+ * @param iter is a pointer to the current row in the GtkTreeModel
+ * @return true if the current row is a separator, false otherwise
+ */
+static gboolean
+status_menu_row_is_separator (GtkTreeModel *model,
+                              GtkTreeIter *iter,
+                              gpointer /*data*/);
+
+
+/** Trigger the appropriate action when a choice is made in the StatusMenu.
+ *
+ * It will update the GmConf key with the chosen value or display a popup 
+ * allowing to add or remove status messages.
+ *
+ * @param box is a pointer to the GtkComboBox
+ * @param data is a pointer to the StatusMenu
+ */
+static void 
+status_menu_option_changed (GtkComboBox *box,
+                            gpointer data);
+
+
+/**
+ * GmConf notifiers
+ */
+
+/** This notifier is triggered when one of the custom messages list is updated. 
+ *
+ * It updates the StatusMenu content with the new values.
+ *
+ * @param id is the GmConf notifier id
+ * @param entry is the GmConfEntry for which the notification was triggered
+ * @param data is a pointer to the StatusMenu
+ */
+static void
+status_menu_custom_messages_changed (gpointer id,
+                                     GmConfEntry *entry,
+                                     gpointer data);
+
+
+/** This notifier is triggered when the long status message is modified. 
+ *
+ * It updates the StatusMenu content with the new value as current choice.
+ *
+ * @param id is the GmConf notifier id
+ * @param entry is the GmConfEntry for which the notification was triggered
+ * @param data is a pointer to the StatusMenu
+ */
+static void
+long_status_message_changed (gpointer id,
+                             GmConfEntry *entry,
+                             gpointer data);
+
+
+/** This notifier is triggered when the short status message is modified. 
+ *
+ * It updates the StatusMenu content with the new value as current choice.
+ *
+ * @param id is the GmConf notifier id
+ * @param entry is the GmConfEntry for which the notification was triggered
+ * @param data is a pointer to the StatusMenu
+ */
+static void
+short_status_message_changed (gpointer id,
+                              GmConfEntry *entry,
+                              gpointer data);
+
+
+/**
+ * Static methods
+ */
+
+/** This function populates the StatusMenu with its initial content. Content is 
+ * taken from the GmConf keys used by the StatusMenu.
+ *
+ * @param self is the StatusMenu
+ */
+static void
+status_menu_populate (StatusMenu *self);
+
+
+/** This function updates the default active status in the StatusMenu.
+ *
+ * @param self is the StatusMenu
+ * @param short_status is the short status of the current status
+ * @param long_status is the long status description of the current status
+ */
+static void
+status_menu_set_option (StatusMenu *self,
+                        const char *short_status,
+                        const char *long_status);
+
+
+/** This function presents a popup allowing to remove some of the user defined
+ * status messages.
+ *
+ * @param self is the StatusMenu
+ */
+static void
+status_menu_clear_status_message_dialog_run (StatusMenu *self);
+
+
+/** This function runs a dialog allowing the user to define custom long status
+ * messages that he will be able to publish.
+ *
+ * @param self is the StatusMenu
+ * @param option is the defined message type (TYPE_CUSTOM_ONLINE, 
+ * TYPE_CUSTOM_AWAY, TYPE_CUSTOM_DND)
+ */
+static void
+status_menu_new_status_message_dialog_run (StatusMenu *self,
+                                           int option);
+
+
+/* 
+ * GObject stuff 
+ */
+static GObjectClass *parent_class = NULL;
+
+static void status_menu_class_init (gpointer g_class,
+                                    gpointer class_data);
+
+static void status_menu_init (StatusMenu *);
+
+static void status_menu_dispose (GObject *obj);
+
+static void status_menu_finalize (GObject *obj);
+
+
+/* 
+ * Callbacks
+ */
+static gboolean
+status_menu_row_is_separator (GtkTreeModel *model,
+                              GtkTreeIter *iter,
+                              gpointer /*data*/)
+{
+  gboolean is_separator;
+
+  gtk_tree_model_get (model, iter, COL_SEPARATOR, &is_separator, -1);
+
+  return is_separator;
+}
+
+
+static void 
+status_menu_option_changed (GtkComboBox *box,
+                            gpointer data)
+{
+  std::stringstream conf_status;
+
+  GtkTreeIter iter;
+  
+  int i = 0;
+  gchar* status = NULL;
+
+  GtkTreeModel* model = NULL;
+  StatusMenu* self = STATUS_MENU (data);
+
+  g_return_if_fail (self != NULL);
+
+  if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (box), &iter)) {
+
+    model = gtk_combo_box_get_model (GTK_COMBO_BOX (box));
+    gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, COL_MESSAGE_TYPE, &i, 
+                        COL_MESSAGE, &status, -1);
+
+    switch (i)
+      {
+      case TYPE_ONLINE:
+        gm_conf_set_string (PERSONAL_DATA_KEY "short_status", "online");
+        gm_conf_set_string (PERSONAL_DATA_KEY "long_status", statuses[TYPE_ONLINE]);
+        break;
+
+      case TYPE_AWAY:
+        gm_conf_set_string (PERSONAL_DATA_KEY "short_status", "away");
+        gm_conf_set_string (PERSONAL_DATA_KEY "long_status", statuses[TYPE_AWAY]);
+        break;
+
+      case TYPE_DND:
+        gm_conf_set_string (PERSONAL_DATA_KEY "short_status", "dnd");
+        gm_conf_set_string (PERSONAL_DATA_KEY "long_status", statuses[TYPE_DND]);
+        break;
+
+      case TYPE_CUSTOM_ONLINE:
+        gm_conf_set_string (PERSONAL_DATA_KEY "short_status", "online");
+        gm_conf_set_string (PERSONAL_DATA_KEY "long_status", status);
+        break;
+
+      case TYPE_CUSTOM_AWAY:
+        gm_conf_set_string (PERSONAL_DATA_KEY "short_status", "away");
+        gm_conf_set_string (PERSONAL_DATA_KEY "long_status", status);
+        break;
+
+      case TYPE_CUSTOM_DND:
+        gm_conf_set_string (PERSONAL_DATA_KEY "short_status", "dnd");
+        gm_conf_set_string (PERSONAL_DATA_KEY "long_status", status);
+        break;
+
+      case TYPE_CUSTOM_ONLINE_NEW:
+        status_menu_new_status_message_dialog_run (self, TYPE_CUSTOM_ONLINE);
+        break;
+
+      case TYPE_CUSTOM_AWAY_NEW:
+        status_menu_new_status_message_dialog_run (self, TYPE_CUSTOM_AWAY);
+        break;
+
+      case TYPE_CUSTOM_DND_NEW:
+        status_menu_new_status_message_dialog_run (self, TYPE_CUSTOM_DND);
+        break;
+
+      case TYPE_CLEAR:
+        status_menu_clear_status_message_dialog_run (self);
+        break;
+
+      default:
+        break;
+      }
+
+    g_free (status);
+  }
+}
+
+
+static void
+status_menu_custom_messages_changed (gpointer /*id*/,
+                                     GmConfEntry *entry,
+                                     gpointer data)
+{
+  GtkTreePath *type_path = NULL;
+  GtkTreeIter iter;
+  GdkPixbuf* icon = NULL;
+  int i = 0;
+  int category_option = 0;
+  int option = 0;
+  bool valid = false;
+  gchar *type_path_str = NULL;
+  StatusMenu *self = STATUS_MENU (data);
+  std::string key = gm_conf_entry_get_key (entry);
+  GSList *list = gm_conf_entry_get_list (entry);
+  GSList *liter = list;
+
+  if (key == PERSONAL_DATA_KEY "online_custom_status") {
+
+    category_option = TYPE_CUSTOM_ONLINE_NEW;
+    option = TYPE_CUSTOM_ONLINE;
+  }
+  else if (key == PERSONAL_DATA_KEY "away_custom_status") {
+
+    category_option = TYPE_CUSTOM_AWAY_NEW;
+    option = TYPE_CUSTOM_AWAY;
+  }
+  else if (key == PERSONAL_DATA_KEY "dnd_custom_status") {
+
+    category_option = TYPE_CUSTOM_DND_NEW;
+    option = TYPE_CUSTOM_DND;
+  }
+
+  // Remove old entries
+  valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->priv->list_store), &iter);
+  while (valid) {
+
+    gtk_tree_model_get (GTK_TREE_MODEL (self->priv->list_store), &iter, COL_MESSAGE_TYPE, &i, -1); 
+
+    if (i == category_option) {
+
+      // Remember the path of the category first item
+      if (!type_path_str) {
+
+        type_path = gtk_tree_model_get_path (GTK_TREE_MODEL (self->priv->list_store), &iter);
+        type_path_str = gtk_tree_path_to_string (type_path);
+        gtk_tree_path_free (type_path);
+        type_path = NULL;
+      }
+    }
+
+    if (i == option) 
+      valid = gtk_list_store_remove (GTK_LIST_STORE (self->priv->list_store), &iter);
+    else
+      valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (self->priv->list_store), &iter);
+  };
+
+  // Add the new items
+  if (type_path_str 
+      && gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (self->priv->list_store), &iter, type_path_str)) {
+
+    icon = gtk_widget_render_icon (GTK_WIDGET (self),
+                                   stock_status [option - NUM_STATUS_TYPES - 1],
+                                   GTK_ICON_SIZE_MENU, NULL);
+    while (liter) {
+
+      gtk_list_store_insert_after (GTK_LIST_STORE (self->priv->list_store), &iter, &iter);
+      gtk_list_store_set (GTK_LIST_STORE (self->priv->list_store), &iter,
+                          COL_ICON, icon, 
+                          COL_MESSAGE, (char*) (liter->data), 
+                          COL_MESSAGE_TYPE, option,
+                          COL_SEPARATOR, false, 
+                          -1); 
+
+      liter = g_slist_next (liter);
+    }
+  
+    g_object_unref (icon);
+  }
+
+  g_slist_foreach (list, (GFunc) g_free, NULL);
+  g_slist_free (list);
+}
+
+
+static void
+long_status_message_changed (gpointer /*id*/,
+                             GmConfEntry *entry,
+                             gpointer data)
+{
+  StatusMenu* self = STATUS_MENU (data);
+  const char* long_status = NULL;
+  char* short_status = NULL;
+
+  g_return_if_fail (self != NULL);
+
+  short_status = gm_conf_get_string (PERSONAL_DATA_KEY "short_status");
+  long_status = gm_conf_entry_get_string (entry);
+
+  status_menu_set_option (self, short_status, long_status);
+
+  g_free (short_status);
+}
+
+
+static void
+short_status_message_changed (gpointer /*id*/,
+                              GmConfEntry *entry,
+                              gpointer data)
+{
+  StatusMenu* self = STATUS_MENU (data);
+  const char* short_status = NULL;
+  char* long_status = NULL;
+
+  g_return_if_fail (self != NULL);
+
+  short_status = gm_conf_entry_get_string (entry);
+  long_status = gm_conf_get_string (PERSONAL_DATA_KEY "long_status");
+
+  status_menu_set_option (self, short_status, long_status);
+
+  g_free (long_status);
+}
+
+
+
+/*
+ * Static methods
+ */
+static void
+status_menu_populate (StatusMenu *self)
+{
+  GSList *custom_status = NULL;
+  GSList *liter = NULL;
+  GtkTreeIter iter;
+  GdkPixbuf* icon = NULL;
+
+  for (int i = 0 ; i < NUM_STATUS_TYPES ; i++) {
+
+    custom_status = gm_conf_get_string_list (status_types_keys[i]);
+    liter = custom_status;
+
+    icon = gtk_widget_render_icon (GTK_WIDGET (self),
+                                   stock_status [i],
+                                   GTK_ICON_SIZE_MENU, NULL);
+
+    gtk_list_store_append (GTK_LIST_STORE (self->priv->list_store), &iter);
+    gtk_list_store_set (GTK_LIST_STORE (self->priv->list_store), &iter,
+                        COL_ICON, icon, 
+                        COL_MESSAGE, statuses[i], 
+                        COL_MESSAGE_TYPE, i,
+                        COL_SEPARATOR, false, 
+                        -1); 
+
+    gtk_list_store_append (GTK_LIST_STORE (self->priv->list_store), &iter);
+    gtk_list_store_set (GTK_LIST_STORE (self->priv->list_store), &iter,
+                        COL_ICON, icon, 
+                        COL_MESSAGE, _("Custom message..."), 
+                        COL_MESSAGE_TYPE, NUM_STATUS_CUSTOM_TYPES + (i + 1),
+                        COL_SEPARATOR, false, 
+                        -1); 
+
+    while (liter) {
+
+      gtk_list_store_append (GTK_LIST_STORE (self->priv->list_store), &iter);
+      gtk_list_store_set (GTK_LIST_STORE (self->priv->list_store), &iter,
+                          COL_ICON, icon, 
+                          COL_MESSAGE, (char*) (liter->data), 
+                          COL_MESSAGE_TYPE, NUM_STATUS_TYPES + (i + 1),
+                          COL_SEPARATOR, false, 
+                          -1); 
+
+      liter = g_slist_next (liter);
+    }
+
+    gtk_list_store_append (GTK_LIST_STORE (self->priv->list_store), &iter);
+    gtk_list_store_set (GTK_LIST_STORE (self->priv->list_store), &iter,
+                        COL_SEPARATOR, true, 
+                        -1); 
+
+    g_slist_foreach (custom_status, (GFunc) g_free, NULL);
+    g_slist_free (custom_status);
+    g_object_unref (icon);
+  }
+
+  /* Clear message */
+  icon = gtk_widget_render_icon (GTK_WIDGET (self),
+                                 GTK_STOCK_CLEAR,
+                                 GTK_ICON_SIZE_MENU, NULL);
+  gtk_list_store_append (GTK_LIST_STORE (self->priv->list_store), &iter);
+  gtk_list_store_set (GTK_LIST_STORE (self->priv->list_store), &iter,
+                      COL_ICON, icon,
+                      COL_MESSAGE, _("Clear"), 
+                      COL_MESSAGE_TYPE, TYPE_CLEAR,
+                      COL_SEPARATOR, false, 
+                      -1); 
+  g_object_unref (icon);
+}
+
+
+static void
+status_menu_set_option (StatusMenu *self,
+                        const char *short_status,
+                        const char *long_status)
+{
+  GtkTreeIter iter;
+
+  bool valid = false;
+  gchar *status = NULL;
+  int i = 0;
+  int cpt = 0;
+
+  g_return_if_fail (short_status != NULL && long_status != NULL);
+
+  valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->priv->list_store), &iter);
+  while (valid) {
+
+    gtk_tree_model_get (GTK_TREE_MODEL (self->priv->list_store), &iter, 
+                        COL_MESSAGE_TYPE, &i,
+                        COL_MESSAGE, &status, -1); 
+
+    if (i == TYPE_CUSTOM_ONLINE || i == TYPE_CUSTOM_AWAY || i == TYPE_CUSTOM_DND) {
+      if (!strcmp (status_types_names[i - NUM_STATUS_TYPES - 1], short_status) && !strcmp (long_status, status))
+        break;
+    }
+    if (i == TYPE_ONLINE || i == TYPE_AWAY || i == TYPE_DND) {
+      if (!strcmp (status_types_names[i], short_status) && !strcmp (long_status, status))
+        break;
+    }
+
+    g_free (status);
+
+    cpt++;
+    valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (self->priv->list_store), &iter);
+  }
+
+  if (valid) 
+    gtk_combo_box_set_active (GTK_COMBO_BOX (self), cpt);
+}
+
+
+static void
+status_menu_clear_status_message_dialog_run (StatusMenu *self)
+{
+  GtkTreeIter iter, liter;
+
+  GSList *conf_list [3] = { NULL, NULL, NULL };
+  GtkWidget *dialog = NULL;
+  GtkWidget *vbox = NULL;
+  GtkWidget *tree_view = NULL;
+
+  GdkPixbuf *pixbuf = NULL;
+  GtkTreeSelection *selection = NULL;
+  GtkListStore *list_store = NULL;
+  GtkCellRenderer *renderer = NULL;
+  GtkTreeViewColumn *column = NULL;
+  GtkWidget *label = NULL;
+
+  bool close = false;
+  int response = 0;
+  int i = 0;
+  int current_option = 0;
+  gchar *message = NULL;
+
+  dialog = gtk_dialog_new_with_buttons (_("Custom Message"),
+                                        self->priv->parent,
+                                        (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
+                                        GTK_STOCK_DELETE,
+                                        GTK_RESPONSE_APPLY,
+                                        GTK_STOCK_CLOSE,
+                                        GTK_RESPONSE_CLOSE,
+                                        NULL);
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
+  gtk_window_set_icon_name (GTK_WINDOW (dialog), GTK_STOCK_DELETE);
+
+  vbox = gtk_vbox_new (false, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
+  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), vbox, false, false, 2);
+
+
+  label = gtk_label_new (_("Delete custom messages:"));
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_box_pack_start (GTK_BOX (vbox), label, false, false, 2);
+
+  list_store = gtk_list_store_new (3,
+                                   GDK_TYPE_PIXBUF,
+                                   G_TYPE_STRING,
+                                   G_TYPE_INT);
+  tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (list_store));
+  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), false);
+
+  column = gtk_tree_view_column_new ();
+  renderer = gtk_cell_renderer_pixbuf_new ();
+  gtk_tree_view_column_pack_start (column, renderer, FALSE);
+  gtk_tree_view_column_set_attributes (column, renderer,
+                                       "pixbuf", 0,
+                                       NULL);
+
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_tree_view_column_pack_start (column, renderer, FALSE);
+  gtk_tree_view_column_set_attributes (column, renderer,
+                                       "text", 1,
+                                       NULL);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
+  gtk_box_pack_start (GTK_BOX (vbox), tree_view, FALSE, FALSE, 2);
+
+  if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->priv->list_store), &iter)) {
+
+    do {
+
+      gtk_tree_model_get (GTK_TREE_MODEL (self->priv->list_store), &iter,
+                          COL_MESSAGE_TYPE, &i, -1);
+
+      if (i == TYPE_CUSTOM_ONLINE || i == TYPE_CUSTOM_AWAY || i == TYPE_CUSTOM_DND) {
+
+        gtk_tree_model_get (GTK_TREE_MODEL (self->priv->list_store), &iter,
+                            COL_ICON, &pixbuf, 
+                            COL_MESSAGE, &message, -1);
+
+        gtk_list_store_append (GTK_LIST_STORE (list_store), &liter);
+        gtk_list_store_set (GTK_LIST_STORE (list_store), &liter, 
+                            0, pixbuf, 
+                            1, message,
+                            2, i, -1);
+        g_free (message);
+        g_object_unref (pixbuf);
+      }
+
+    } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (self->priv->list_store), &iter));
+  }
+
+  gtk_widget_show_all (dialog);
+  while (!close) {
+    response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+    switch (response)
+      {
+        case GTK_RESPONSE_APPLY:
+          selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+          if (gtk_tree_selection_get_selected (selection, NULL, &iter)) 
+            gtk_list_store_remove (GTK_LIST_STORE (list_store), &iter);
+        break;
+
+        case GTK_RESPONSE_CLOSE:
+        default:
+        close = true;
+      }
+  }
+
+  if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (list_store), &iter)) {
+
+    do {
+
+      gtk_tree_model_get (GTK_TREE_MODEL (list_store), &iter,
+                          1, &message,
+                          2, &i, -1);
+      conf_list[i - NUM_STATUS_TYPES - 1] = 
+        g_slist_append (conf_list[i - NUM_STATUS_TYPES - 1], g_strdup (message));
+      g_free (message);
+    } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (list_store), &iter));
+  }
+
+  for (int j = 0 ; j < 3 ; j++) {
+    gm_conf_set_string_list (status_types_keys[j], conf_list[j]);
+    g_slist_foreach (conf_list[j], (GFunc) g_free, NULL);
+    g_slist_free (conf_list[j]);
+  }
+
+  status_menu_set_option (self, status_types_names[current_option], statuses[current_option]);
+
+  gtk_widget_destroy (dialog);
+}
+
+
+static void
+status_menu_new_status_message_dialog_run (StatusMenu *self,
+                                           int option)
+{
+  std::stringstream conf_status;
+  gchar *short_status = NULL;
+  gchar *long_status = NULL;
+
+  GSList *clist = NULL;
+  GtkWidget *dialog = NULL;
+  GtkWidget *label = NULL;
+  GtkWidget *entry = NULL;
+  GtkWidget *vbox = NULL;
+  GtkWidget *hbox = NULL;
+  GtkWidget *image = NULL;
+
+  GdkPixbuf* icon = NULL;
+
+  const char *message = NULL;
+
+  short_status = gm_conf_get_string (PERSONAL_DATA_KEY "short_status");
+  long_status = gm_conf_get_string (PERSONAL_DATA_KEY "long_status");
+
+  dialog = gtk_dialog_new_with_buttons (_("Custom Message"),
+                                        self->priv->parent,
+                                        (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
+                                        GTK_STOCK_OK,
+                                        GTK_RESPONSE_ACCEPT,
+                                        NULL);
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
+
+  vbox = gtk_vbox_new (false, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
+  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), vbox, false, false, 2);
+
+  hbox = gtk_hbox_new (false, 2);
+  icon = gtk_widget_render_icon (GTK_WIDGET (self),
+                                 stock_status [option - NUM_STATUS_TYPES - 1],
+                                 GTK_ICON_SIZE_MENU, NULL);
+  gtk_window_set_icon (GTK_WINDOW (dialog), icon);
+  image = gtk_image_new_from_pixbuf (icon);
+  g_object_unref (icon);
+  gtk_box_pack_start (GTK_BOX (hbox), image, false, false, 2);
+
+  label = gtk_label_new (_("Define a custom message:"));
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_box_pack_start (GTK_BOX (hbox), label, false, false, 2);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, false, false, 2);
+
+  entry = gtk_entry_new ();
+  gtk_entry_set_activates_default (GTK_ENTRY (entry), true);
+  gtk_box_pack_start (GTK_BOX (vbox), entry, false, false, 2);
+
+  gtk_widget_show_all (dialog);
+  switch (gtk_dialog_run (GTK_DIALOG (dialog))) {
+
+  case GTK_RESPONSE_ACCEPT:
+    message = gtk_entry_get_text (GTK_ENTRY (entry));
+    clist = gm_conf_get_string_list (status_types_keys[option - NUM_STATUS_TYPES - 1]);
+    if (strcmp (message, "")) { 
+      clist = g_slist_append (clist, g_strdup (message));
+      gm_conf_set_string_list (status_types_keys[option - NUM_STATUS_TYPES - 1], clist);
+      gm_conf_set_string (PERSONAL_DATA_KEY "long_status", message);
+      gm_conf_set_string (PERSONAL_DATA_KEY "short_status", status_types_names[option - NUM_STATUS_TYPES - 1]);
+    }
+    else {
+      status_menu_set_option (self, short_status, long_status);
+    }
+    g_slist_foreach (clist, (GFunc) g_free, NULL);
+    g_slist_free (clist);
+    break;
+
+  default:
+    status_menu_set_option (self, short_status, long_status);
+    break;
+  }
+
+  gtk_widget_destroy (dialog);
+
+  g_free (short_status);
+  g_free (long_status);
+}
+
+
+/* 
+ * GObject stuff
+ */
+static void
+status_menu_class_init (gpointer g_class,
+                        gpointer /*class_data*/)
+{
+  GObjectClass *gobject_class = NULL;
+
+  parent_class = (GObjectClass *) g_type_class_peek_parent (g_class);
+
+  gobject_class = (GObjectClass *) g_class;
+  gobject_class->dispose = status_menu_dispose;
+  gobject_class->finalize = status_menu_finalize;
+}
+
+
+static void
+status_menu_init (StatusMenu *self)
+{
+  GtkCellRenderer *renderer = NULL;
+
+  self->priv = new StatusMenuPrivate;
+
+  self->priv->parent = NULL;
+  self->priv->list_store = gtk_list_store_new (NUM_COLUMNS,
+                                               GDK_TYPE_PIXBUF,
+                                               G_TYPE_STRING,
+                                               G_TYPE_INT,
+                                               G_TYPE_BOOLEAN);
+
+  gtk_combo_box_set_model (GTK_COMBO_BOX (self),
+                           GTK_TREE_MODEL (self->priv->list_store));
+
+  renderer = gtk_cell_renderer_pixbuf_new ();
+  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (self), renderer, FALSE);
+  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (self), renderer,
+                                  "pixbuf", COL_ICON, NULL);
+
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (self), renderer, FALSE);
+  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (self), renderer, "text", COL_MESSAGE, NULL);
+  g_object_set (renderer, "width", 130, 
+                "ellipsize-set", true, 
+                "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+
+  status_menu_populate (self);
+
+  gtk_combo_box_set_active (GTK_COMBO_BOX (self), 0);
+
+  gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (self),
+                                        (GtkTreeViewRowSeparatorFunc) status_menu_row_is_separator,
+                                        NULL, NULL);
+  gtk_container_set_border_width (GTK_CONTAINER (self), 0);
+
+  g_signal_connect (G_OBJECT (self), "changed",
+                    G_CALLBACK (status_menu_option_changed), self);
+
+  gm_conf_notifier_add (PERSONAL_DATA_KEY "online_custom_status", 
+                        status_menu_custom_messages_changed, self);
+  gm_conf_notifier_add (PERSONAL_DATA_KEY "away_custom_status", 
+                        status_menu_custom_messages_changed, self);
+  gm_conf_notifier_add (PERSONAL_DATA_KEY "dnd_custom_status", 
+                        status_menu_custom_messages_changed, self);
+
+  gm_conf_notifier_add (PERSONAL_DATA_KEY "long_status", 
+                        long_status_message_changed, self);
+  gm_conf_notifier_add (PERSONAL_DATA_KEY "short_status", 
+                        short_status_message_changed, self);
+}
+
+
+static void
+status_menu_dispose (GObject *obj)
+{
+  StatusMenu *self = NULL;
+
+  self = STATUS_MENU (obj);
+  delete self->priv;
+
+  self->priv = NULL;
+
+  // NULLify everything
+  parent_class->dispose (obj);
+}
+
+
+static void
+status_menu_finalize (GObject *obj)
+{
+  parent_class->finalize (obj);
+}
+
+
+GType
+status_menu_get_type (void)
+{
+  static GType status_menu_type = 0;
+
+  if (status_menu_type == 0) {
+
+    static const GTypeInfo status_menu_info =
+      {
+        sizeof (StatusMenuClass),
+        NULL,
+        NULL,
+        (GClassInitFunc) status_menu_class_init,
+        NULL,
+        NULL,
+        sizeof (StatusMenu),
+        0,
+        (GInstanceInitFunc) status_menu_init,
+        NULL
+      };
+
+    status_menu_type = g_type_register_static (GTK_TYPE_COMBO_BOX,
+                                               "StatusMenu",
+                                               &status_menu_info,
+                                               (GTypeFlags) 0);
+  }
+
+  return status_menu_type;
+}
+
+
+GtkWidget *
+status_menu_new ()
+{
+  return GTK_WIDGET (STATUS_MENU (g_object_new (STATUS_MENU_TYPE, NULL)));
+}
+
+
+void
+status_menu_set_parent_window (StatusMenu *self,
+                               GtkWindow *parent)
+{
+  self->priv->parent = parent;
+}

Added: trunk/src/gui/statusmenu.h
==============================================================================
--- (empty file)
+++ trunk/src/gui/statusmenu.h	Sun Mar  2 11:03:36 2008
@@ -0,0 +1,100 @@
+
+/* Ekiga -- A VoIP and Video-Conferencing application
+ * Copyright (C) 2000-2008 Damien Sandras
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ *
+ * Ekiga is licensed under the GPL license and as a special exception,
+ * you have permission to link or otherwise combine this program with the
+ * programs OPAL, OpenH323 and PWLIB, and distribute the combination,
+ * without applying the requirements of the GNU GPL to the OPAL, OpenH323
+ * and PWLIB programs, as long as you do follow the requirements of the
+ * GNU GPL for all the rest of the software thus combined.
+ */
+
+
+/*
+ *                         statusmenu.h  -  description
+ *                         -------------------------------
+ *   begin                : Mon Jan 28 2008
+ *   copyright            : (C) 2000-2008 by Damien Sandras 
+ *   description          : Contains a StatusMenu
+ *
+ */
+
+
+
+#ifndef __STATUS_MENU_H
+#define __STATUS_MENU_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include <ptlib.h>
+#include <opal/manager.h>
+
+#include "call.h"
+
+
+/** This implements a StatusMenu.
+ */
+
+G_BEGIN_DECLS
+
+#define STATUS_MENU_TYPE (status_menu_get_type ())
+#define STATUS_MENU(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), STATUS_MENU_TYPE, StatusMenu))
+#define STATUS_MENU_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), STATUS_MENU_TYPE, StatusMenuClass))
+#define IS_STATUS_MENU(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), STATUS_MENU_TYPE))
+#define IS_STATUS_MENU_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), STATUS_MENU_TYPE))
+#define STATUS_MENU_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), STATUS_MENU_TYPE, StatusMenuClass))
+
+typedef struct _StatusMenu StatusMenu;
+typedef struct _StatusMenuPrivate StatusMenuPrivate;
+typedef struct _StatusMenuClass StatusMenuClass;
+
+struct _StatusMenu
+{
+  GtkComboBox parent;
+
+  StatusMenuPrivate *priv;
+};
+
+
+struct _StatusMenuClass
+{
+  GtkButtonClass parent_class;
+};
+
+GType status_menu_get_type (void);
+
+
+/** Create a new StatusMenu 
+ */
+GtkWidget *status_menu_new ();
+
+
+/** Set parent window for a StatusMenu 
+ *
+ * @param self   The StatusMenu.
+ * @param parent The parent window.
+ */
+void status_menu_set_parent_window (StatusMenu *self,
+                                    GtkWindow *parent);
+
+
+G_END_DECLS
+
+#endif /* __STATUS_MENU_H */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]