[gnome-system-tools/users-ui-redesign] Implement add user dialog



commit f5515927b8118f6f0b668813d99bdd5d64aa3af2
Author: Milan Bouchet-Valat <nalimilan club fr>
Date:   Fri Nov 20 19:45:18 2009 +0100

    Implement add user dialog
    
    Very simple dialog that asks for Real name and Login, trying to propose nice logins by transliterating the Real name to ASCII and removing invalid chars. The user is created with the default profile, and the password edit dialog is run, since that's what most people need to configure immediately.
    
    This implied changing on_table_selection_changed() and users_table_get_current() not to crash when no user is selected (needed to ensure only the new user is selected).  users_table_add_user() now returns the path to the user, useful to select it; added function users_table_select_path() for that, converting to GtkModelFilter path. Removed old on_user_new_clicked() callback. Fixed setting UID when applying profile.
    
    New on_user_new_name_changed() callback that fills the combo box with possibly nice logins, trying hard to get something useful.

 interfaces/users.ui       |  151 +++++++++++++++++++++++++
 src/users/callbacks.c     |   43 +------
 src/users/main.c          |    1 -
 src/users/user-profiles.c |    1 +
 src/users/user-settings.c |  267 +++++++++++++++++++++++++++++++++++++++++++++
 src/users/users-table.c   |   35 ++++++-
 src/users/users-table.h   |   26 +++--
 7 files changed, 474 insertions(+), 50 deletions(-)
---
diff --git a/interfaces/users.ui b/interfaces/users.ui
index d7b9284..baffda8 100644
--- a/interfaces/users.ui
+++ b/interfaces/users.ui
@@ -66,6 +66,12 @@
       <column type="gchararray"/>
     </columns>
   </object>
+  <object class="GtkListStore" id="liststore2">
+    <columns>
+      <!-- column-name login -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
   <object class="GtkWindow" id="users_dialog">
     <property name="border_width">6</property>
     <child>
@@ -109,6 +115,7 @@
                     <property name="receives_default">True</property>
                     <property name="use_underline">True</property>
                     <property name="use_stock">True</property>
+                    <signal name="clicked" handler="on_user_new"/>
                   </object>
                   <packing>
                     <property name="position">0</property>
@@ -2819,4 +2826,148 @@
       <action-widget response="-5">user_profile_validate_button</action-widget>
     </action-widgets>
   </object>
+  <object class="GtkDialog" id="user_new_dialog">
+    <property name="border_width">12</property>
+    <property name="title" translatable="yes">Create New User</property>
+    <property name="resizable">False</property>
+    <property name="modal">True</property>
+    <property name="destroy_with_parent">True</property>
+    <property name="type_hint">dialog</property>
+    <property name="skip_taskbar_hint">True</property>
+    <property name="skip_pager_hint">True</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog-vbox14">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">24</property>
+        <child>
+          <object class="GtkTable" id="table2">
+            <property name="visible">True</property>
+            <property name="n_rows">3</property>
+            <property name="n_columns">2</property>
+            <property name="column_spacing">12</property>
+            <property name="row_spacing">12</property>
+            <child>
+              <object class="GtkEntry" id="user_new_name">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="invisible_char">&#x2022;</property>
+                <property name="activates_default">True</property>
+                <signal name="changed" handler="on_user_new_name_changed"/>
+              </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="y_options">GTK_FILL</property>
+                <property name="y_padding">12</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label2">
+                <property name="visible">True</property>
+                <property name="xalign">1</property>
+                <property name="label" translatable="yes">_Name:</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">user_name_entry</property>
+              </object>
+              <packing>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+                <property name="y_options">GTK_FILL</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label3">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Create a new user</property>
+                <property name="track_visited_links">False</property>
+                <attributes>
+                  <attribute name="size" value="12000"/>
+                </attributes>
+              </object>
+              <packing>
+                <property name="right_attach">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label4">
+                <property name="visible">True</property>
+                <property name="xalign">1</property>
+                <property name="label" translatable="yes">_Short Name:</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="top_attach">2</property>
+                <property name="bottom_attach">3</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkComboBoxEntry" id="user_new_login">
+                <property name="visible">True</property>
+                <property name="model">liststore2</property>
+                <property name="text_column">0</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">2</property>
+                <property name="bottom_attach">3</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area14">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="user_new_cancel_button">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</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>
+            <child>
+              <object class="GtkButton" id="user_new_validate_button">
+                <property name="label">gtk-ok</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="has_default">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">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">user_new_cancel_button</action-widget>
+      <action-widget response="-5">user_new_validate_button</action-widget>
+    </action-widgets>
+  </object>
 </interface>
diff --git a/src/users/callbacks.c b/src/users/callbacks.c
index db88143..8761d4d 100644
--- a/src/users/callbacks.c
+++ b/src/users/callbacks.c
@@ -128,12 +128,16 @@ on_table_selection_changed (GtkTreeSelection *selection, gpointer data)
 		user = users_table_get_current ();
 	}
 
+	/* this happens when we unselect all users before selecting a single one */
+	if (!user)
+		return;
+
 	actions_set_sensitive (table, count, user);
 
 	/* Show the settings for the selected user */
 	user_settings_set (user);
-	if (user)
-		g_object_unref (user);
+
+	g_object_unref (user);
 }
 
 static void
@@ -223,7 +227,7 @@ on_popup_add_activate (GtkAction *action, gpointer data)
 	if (table == TABLE_GROUPS)
 		on_group_new_clicked (NULL, NULL);
 	else if (table == TABLE_USERS)
-		on_user_new_clicked (NULL, NULL);
+		on_user_new (NULL, NULL);
 }
 
 void
@@ -251,39 +255,6 @@ on_popup_delete_activate (GtkAction *action, gpointer data)
 /* Users Tab */
 
 void
-on_user_new_clicked (GtkButton *button, gpointer user_data)
-{
-	GtkWidget *dialog;
-	OobsUsersConfig *config;
-	OobsUser *user;
-	OobsList *users_list;
-	OobsListIter list_iter;
-	gint response;
-#if 0
-	dialog = user_settings_dialog_new (NULL);
-	gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (tool->main_dialog));
-	response = user_settings_dialog_run (dialog);
-#endif
-	if (response == GTK_RESPONSE_OK) {
-		user = user_settings_dialog_get_data (dialog);
-
-		if (!user) /* Means an error has already occurred and been displayed, stop here */
-			return;
-
-		config = OOBS_USERS_CONFIG (GST_USERS_TOOL (tool)->users_config);
-		users_list = oobs_users_config_get_users (config);
-		oobs_list_append (users_list, &list_iter);
-		oobs_list_set (users_list, &list_iter, user);
-
-		/* Avoid showing the new user or trying to commit group changes if the user has not been created */
-		if (gst_tool_commit (tool, GST_USERS_TOOL (tool)->users_config) == OOBS_RESULT_OK) {
-			gst_tool_commit (tool, GST_USERS_TOOL (tool)->groups_config);
-			users_table_add_user (user, &list_iter);
-		}
-	}
-}
-
-void
 on_user_settings_clicked (GtkButton *button, gpointer user_data)
 {
 	GtkWidget *table, *dialog;
diff --git a/src/users/main.c b/src/users/main.c
index 25cd45c..f1d25af 100644
--- a/src/users/main.c
+++ b/src/users/main.c
@@ -47,7 +47,6 @@ static GstDialogSignal signals[] = {
 	{ "user_settings_passwd1",		"changed",		G_CALLBACK (on_user_settings_passwd_changed) },
 
 	/* Main dialog callbacks, users tab */
-	{ "user_new",				"clicked",		G_CALLBACK (on_user_new_clicked) },
 	{ "user_delete",                	"clicked",       	G_CALLBACK (on_user_delete_clicked) },
 	{ "manage_groups",                      "clicked",              G_CALLBACK (on_manage_groups_clicked) },
 	
diff --git a/src/users/user-profiles.c b/src/users/user-profiles.c
index 94dd9a7..22437b4 100644
--- a/src/users/user-profiles.c
+++ b/src/users/user-profiles.c
@@ -381,6 +381,7 @@ gst_user_profiles_apply (GstUserProfiles *profiles,
 
 	/* default UID */
 	uid = user_settings_find_new_uid (profile->uid_min, profile->uid_max);
+	oobs_user_set_uid (user, uid);
 
 	/* default home prefix */
 	home = g_build_path (G_DIR_SEPARATOR_S,
diff --git a/src/users/user-settings.c b/src/users/user-settings.c
index a7a0a1d..e9d7f1d 100644
--- a/src/users/user-settings.c
+++ b/src/users/user-settings.c
@@ -45,6 +45,10 @@
 
 extern GstTool *tool;
 
+void   on_edit_user_passwd  (GtkButton *button,
+                             gpointer   user_data);
+
+
 static gboolean
 check_user_delete (OobsUser *user)
 {
@@ -816,6 +820,269 @@ user_settings_dialog_get_data (GtkWidget *dialog)
 }
 
 /*
+ * Callback for user_new_name entry: on every change, fill the combo entry
+ * with proposed logins.
+ */
+void
+on_user_new_name_changed (GtkEditable *user_name, gpointer user_data)
+{
+	GtkWidget *user_login;
+	GtkTreeModel *model;
+	const char *name;
+	char *lc_name, *ascii_name, *stripped_name;
+	char **words1;
+	char **words2 = NULL;
+	char **w1, **w2;
+	char *c;
+	char *unicode_fallback = "?";
+	GString *first_word, *last_word;
+	GString *item1, *item2, *item3, *item4;
+	int len;
+	int nwords1, nwords2, i;
+
+	user_login = gst_dialog_get_widget (tool->main_dialog, "user_new_login");
+	model = gtk_combo_box_get_model (GTK_COMBO_BOX (user_login));
+	gtk_list_store_clear (GTK_LIST_STORE (model));
+	gtk_combo_box_set_active (GTK_COMBO_BOX (user_login), -1);
+
+	name = gtk_entry_get_text (GTK_ENTRY (user_name));
+
+	if (name == NULL || strlen (name) <= 0)
+		return;
+
+	ascii_name = g_convert_with_fallback (name, -1, "ASCII//TRANSLIT", "UTF-8",
+	                                      unicode_fallback, NULL, NULL, NULL);
+
+	lc_name = g_ascii_strdown (ascii_name, -1);
+
+	/* remove all non ASCII alphanumeric chars from the name, apart from
+	 * the few allowed symbols, and ensure the first char is a letter */
+	stripped_name = g_strnfill (strlen (lc_name) + 1, '\0');
+	i = 0;
+	for (c = ascii_name; *c; c++) {
+		if ( (c == lc_name && !g_ascii_islower (*c))
+		     || !(g_ascii_isdigit (*c) || g_ascii_islower (*c)
+		          || *c == ' ' || *c == '-' || *c == '.' || *c == '_'
+		          /* used to track invalid words, removed below */
+		          || *c == '?') )
+			continue;
+
+		    stripped_name[i] = *c;
+		    i++;
+	}
+
+	if (strlen (stripped_name) <= 0) {
+		g_free (ascii_name);
+		g_free (lc_name);
+		g_free (stripped_name);
+		return;
+	}
+
+	/* we split name on spaces, and then on dashes, so that we can treat words
+	 * linked with dashes the same way, i.e. both fully shown, or both abbreviated */
+	words1 = g_strsplit_set (stripped_name, " ", -1);
+	len = g_strv_length (words1);
+
+	g_free (ascii_name);
+	g_free (lc_name);
+	g_free (stripped_name);
+
+
+	/* Concatenate the whole first word with the first letter of each word (item1),
+	 * and the last word with the first letter of each word (item2). item3 and item4
+	 * are symmetrical respectively to item1 and item2.
+	 *
+	 * Constant 5 is the max reasonable number of words we may get when
+	 * splitting on dashes, since we can't guess it at this point,
+	 * and reallocating would be too bad. */
+	item1 = g_string_sized_new (strlen (words1[0]) + len - 1 + 5);
+	item3 = g_string_sized_new (strlen (words1[0]) + len - 1 + 5);
+
+	item2 = g_string_sized_new (strlen (words1[len - 1]) + len - 1 + 5);
+	item4 = g_string_sized_new (strlen (words1[len - 1]) + len - 1 + 5);
+
+	/* again, guess at the max size of names */
+	first_word = g_string_sized_new (20);
+	last_word = g_string_sized_new (20);
+
+	nwords1 = 0;
+	nwords2 = 0;
+	for (w1 = words1; *w1; w1++) {
+		if (strlen (*w1) == 0)
+			continue;
+
+		/* skip words with string '?', most likely resulting
+		 * from failed transliteration to ASCII */
+		if (strstr (*w1, unicode_fallback) != NULL)
+			continue;
+
+		nwords1++; /* count real words, excluding empty string */
+
+		words2 = g_strsplit_set (*w1, "-", -1);
+
+		/* reset last word if a new non-empty word has been found */
+		if (strlen (*words2) > 0)
+			last_word = g_string_set_size (last_word, 0);
+
+		for (w2 = words2; *w2; w2++) {
+			if (strlen (*w2) == 0)
+				continue;
+
+			nwords2++;
+
+			/* part of the first "toplevel" real word */
+			if (nwords1 == 1) {
+				item1 = g_string_append (item1, *w2);
+				first_word = g_string_append (first_word, *w2);
+			}
+			else {
+				item1 = g_string_append_unichar (item1,
+				                                 g_utf8_get_char (*w2));
+				item3 = g_string_append_unichar (item3,
+				                                 g_utf8_get_char (*w2));
+			}
+
+			/* not part of the last "toplevel" word */
+			if (w1 != words1 + len - 1) {
+				item2 = g_string_append_unichar (item2,
+				                                 g_utf8_get_char (*w2));
+				item4 = g_string_append_unichar (item4,
+				                                 g_utf8_get_char (*w2));
+			}
+
+			/* always save current word so that we have it if last one reveals empty */
+			last_word = g_string_append (last_word, *w2);
+		}
+
+		g_strfreev (words2);
+	}
+
+	item2 = g_string_append (item2, last_word->str);
+	item3 = g_string_append (item3, first_word->str);
+	item4 = g_string_prepend (item4, last_word->str);
+
+	if (nwords2 > 0 && !login_exists (item1->str))
+		gtk_combo_box_append_text (GTK_COMBO_BOX (user_login), item1->str);
+
+	/* if there's only one word, would be the same as item1 */
+	if (nwords2 > 1) {
+		/* add other items */
+		if (!login_exists (item2->str))
+			gtk_combo_box_append_text (GTK_COMBO_BOX (user_login), item2->str);
+
+		if (!login_exists (item3->str))
+			gtk_combo_box_append_text (GTK_COMBO_BOX (user_login), item3->str);
+
+		if (!login_exists (item4->str))
+			gtk_combo_box_append_text (GTK_COMBO_BOX (user_login), item4->str);
+
+		/* add the last word */
+		if (!login_exists (last_word->str))
+			gtk_combo_box_append_text (GTK_COMBO_BOX (user_login), last_word->str);
+
+		/* ...and the first one */
+		if (!login_exists (first_word->str))
+			gtk_combo_box_append_text (GTK_COMBO_BOX (user_login), first_word->str);
+	}
+
+
+	gtk_combo_box_set_active (GTK_COMBO_BOX (user_login), 0);
+
+	g_strfreev (words1);
+	g_string_free (first_word, TRUE);
+	g_string_free (last_word, TRUE);
+	g_string_free (item1, TRUE);
+	g_string_free (item2, TRUE);
+	g_string_free (item3, TRUE);
+	g_string_free (item4, TRUE);
+}
+
+/*
+ * Callback for user_new button: run the dialog to enter the user's
+ * real name and login, and create the user with default settings.
+ */
+void
+on_user_new (GtkButton *button, gpointer user_data)
+{
+	int response;
+	GtkWidget *user_new_dialog;
+	GtkWidget *user_name;
+	GtkWidget *user_login;
+	GtkTreeModel *model;
+	GtkTreePath *user_path;
+	OobsUser *user;
+	const char *fullname, *login;
+	GstUserProfile *profile;
+	OobsList *users_list;
+	OobsListIter list_iter;
+	OobsUsersConfig *users_config;
+
+	user_new_dialog = gst_dialog_get_widget (tool->main_dialog, "user_new_dialog");
+	user_name = gst_dialog_get_widget (tool->main_dialog, "user_new_name");
+	user_login = gst_dialog_get_widget (tool->main_dialog, "user_new_login");
+
+	/* clear any text left */
+	gtk_entry_set_text (GTK_ENTRY (user_name), "");
+	model = gtk_combo_box_get_model (GTK_COMBO_BOX (user_login));
+	gtk_list_store_clear (GTK_LIST_STORE (model));
+	gtk_combo_box_set_active (GTK_COMBO_BOX (user_login), -1);
+
+	gtk_window_set_focus (GTK_WINDOW (user_new_dialog), user_name);
+
+	/* run dialog with correct settings */
+	gtk_window_set_transient_for (GTK_WINDOW (user_new_dialog),
+	                              GTK_WINDOW (tool->main_dialog));
+	gst_dialog_add_edit_dialog (tool->main_dialog, GTK_WIDGET (user_new_dialog));
+	response = gtk_dialog_run (GTK_DIALOG (user_new_dialog));
+	gst_dialog_remove_edit_dialog (tool->main_dialog, GTK_WIDGET (user_new_dialog));
+	gtk_widget_hide (GTK_WIDGET (user_new_dialog));
+
+	if (response != GTK_RESPONSE_OK)
+		return;
+
+	/* create user with base data entered by the user */
+	login = gtk_combo_box_get_active_text (GTK_COMBO_BOX (user_login));
+	fullname = gtk_entry_get_text (GTK_ENTRY (user_name));
+	user = oobs_user_new (login);
+	oobs_user_set_full_name (user, fullname);
+
+	g_return_if_fail (user != NULL);
+
+	/* If FALSE, group could not be found or created, which means
+	 * we won't be able to create the new user anyway, so stop here.
+	 * Error dialog has already been shown when trying to commit changes. */
+	if (!set_main_group (user)) {
+		g_object_unref (user);
+		return;
+	}
+
+	/* fill settings with values from default profile */
+	profile = gst_user_profiles_get_default_profile (GST_USERS_TOOL (tool)->profiles);
+	gst_user_profiles_apply (GST_USERS_TOOL (tool)->profiles, profile, user, TRUE);
+
+	users_config = OOBS_USERS_CONFIG (GST_USERS_TOOL (tool)->users_config);
+	users_list = oobs_users_config_get_users (users_config);
+	oobs_list_append (users_list, &list_iter);
+	oobs_list_set (users_list, &list_iter, user);
+
+	/* Commit both users and groups config because of possible memberships
+	 * added by the profile. Avoid showing the new user or trying to commit
+	 * group changes if the user has not been created. */
+	if (gst_tool_commit (tool, OOBS_OBJECT (users_config)) == OOBS_RESULT_OK) {
+		gst_tool_commit (tool, GST_USERS_TOOL (tool)->groups_config);
+		user_path = users_table_add_user (user, &list_iter);
+		users_table_select_path (user_path);
+
+		/* Finally, run the password edit dialog.
+		 * User can hit cancel, leaving the account disabled */
+		on_edit_user_passwd (NULL, NULL);
+	}
+
+	g_object_unref (user);
+	gtk_tree_path_free (user_path);
+}
+
+/*
  * Common to all modular edit dialogs: run the dialog after filling
  * the user's name and face and handling window settings.
  */
diff --git a/src/users/users-table.c b/src/users/users-table.c
index 18c1ea4..b5b272d 100644
--- a/src/users/users-table.c
+++ b/src/users/users-table.c
@@ -174,16 +174,25 @@ users_table_set_user (OobsUser *user, OobsListIter *list_iter, GtkTreeIter *iter
 		g_object_unref (face);
 }
 
-void
+/*
+ * Add an item in the users list. This function is used on start to fill in
+ * all the existing users, and when creating a new user.
+ *
+ * Returns: the path to the new item
+ */
+GtkTreePath *
 users_table_add_user (OobsUser *user, OobsListIter *list_iter)
 {
 	GtkWidget *users_table = gst_dialog_get_widget (GST_TOOL (tool)->main_dialog, "users_table");
 	GtkTreeModel *filter_model = gtk_tree_view_get_model (GTK_TREE_VIEW (users_table));
 	GtkTreeModel *model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (filter_model));
+	GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (users_table));
 	GtkTreeIter iter;
 
 	gtk_list_store_append (GTK_LIST_STORE (model), &iter);
 	users_table_set_user (user, list_iter, &iter);
+
+	return gtk_tree_model_get_path (model, &iter);
 }
 
 void
@@ -196,6 +205,27 @@ users_table_clear (void)
         gtk_list_store_clear (GTK_LIST_STORE (model));
 }
 
+/*
+ * Select the given path, translating it to a row in the filter model. Useful when
+ * we only want to select a newly added item.
+ */
+void
+users_table_select_path (GtkTreePath *path)
+{
+	GtkWidget *users_table = gst_dialog_get_widget (GST_TOOL (tool)->main_dialog, "users_table");
+	GtkTreeModel *filter_model = gtk_tree_view_get_model (GTK_TREE_VIEW (users_table));
+	GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (users_table));
+	GtkTreePath *filter_path;
+
+	filter_path = gtk_tree_model_filter_convert_child_path_to_path
+		(GTK_TREE_MODEL_FILTER (filter_model), path);
+
+	gtk_tree_selection_unselect_all (selection);
+	gtk_tree_selection_select_path (selection, filter_path);
+
+	gtk_tree_path_free (filter_path);
+}
+
 void
 users_table_select_first (void)
 {
@@ -224,6 +254,9 @@ users_table_get_current (void)
 
 	selected = gtk_tree_selection_get_selected_rows (selection, &model);
 
+	if (selected == NULL)
+		return NULL;
+
 	/* Only choose the first selected user */
 	path = (GtkTreePath *) selected->data;
 
diff --git a/src/users/users-table.h b/src/users/users-table.h
index 49372a8..0047b59 100644
--- a/src/users/users-table.h
+++ b/src/users/users-table.h
@@ -40,24 +40,26 @@ enum {
 	COL_USER_LAST
 };
 
-void      create_users_table	   (GstUsersTool *tool);
+void         create_users_table	               (GstUsersTool *tool);
 
-void      users_table_clear        (void);
+void         users_table_clear                 (void);
 
-void      users_table_set_user     (OobsUser     *user,
-                                    OobsListIter *list_iter,
-                                    GtkTreeIter  *iter);
+void         users_table_set_user              (OobsUser     *user,
+                                                OobsListIter *list_iter,
+                                                GtkTreeIter  *iter);
 
-void      users_table_add_user     (OobsUser     *user,
-                                    OobsListIter *list_iter);
+GtkTreePath *users_table_add_user              (OobsUser     *user,
+                                                OobsListIter *list_iter);
 
-void      users_table_select_first (void);
+void         users_table_select_path           (GtkTreePath *path);
 
-OobsUser *users_table_get_current  (void);
+void         users_table_select_first          (void);
 
-void      users_table_actions_set_sensitive (gint      table,
-                                             gint      count,
-                                             OobsUser *user);
+OobsUser    *users_table_get_current           (void);
+
+void         users_table_actions_set_sensitive (gint      table,
+                                                gint      count,
+                                                OobsUser *user);
 
 #endif /* _USERS_TABLE_H */
 



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