glade3 r1908 - in trunk: . gladeui plugins/gtk+



Author: tvb
Date: Tue Sep 16 18:25:52 2008
New Revision: 1908
URL: http://svn.gnome.org/viewvc/glade3?rev=1908&view=rev

Log:
2008-09-16  Pavel Kostyuchenko <ShprotX gmail com>

        * gladeui/glade-app.c:
          Creating toplevel widget through unified glade-palette interface.
          Removed error message when pasting non-toplevel widgets without
          a parent.

        * gladeui/glade-command.h: A new function for getting depth of command recursion

        * gladeui/glade-command.c:
          A new function for getting depth of command recursion.
          A return value of glade_command_set_property_execute function is valid
          and is respected by glade_command_set_properties_list.
          indicate success/failure of their execution.
          Glade-command can be unified to null.
          Setting property command is always executed as a group, so if there is
          any recursive command, they will be added to that group.
          Removed parentless widget message level lowered from critical to
          message.
          Widget is treated as toplevel only if it has no parent.
          Removed an assertion from glade_command_create that doesn't allow
          creation of non-GtkWindow parentless widgets

        * gladeui/glade-editor-property.c:
          Object selection dialog will be optionally filled by parentless
          non-GtkWindow widgets only
          Unparenting root widgets before setting another property to them

        * gladeui/glade-inspector.c:
          Popup for clicking even on empty part of widget list

        * gladeui/glade-palette.h:
          A unified function for creating root widgets

        * gladeui/glade-palette.c:
          A unified function for creating root widgets
          A new button for creating root widgets

        * gladeui/glade-placeholder.[ch]:
          glade_placeholder_get_project has been made public for using in
          glade-popup

        * gladeui/glade-popup.c:
          A new function glade_popup_simple_pop for creating a context menu on
          an empty space of glade-inspector
          New context menu items for adding widgets

        * gladeui/glade-popup.h:
          A new function glade_popup_simple_pop for creating a context menu on
          an empty space of glade-inspector

        * gladeui/glade-project.c:
          Unifying command even if there's redo items.
          Unifying atomic commands only.
          Unifying to null

        * gladeui/glade-property-class.[ch]:
          A new field for making properties that points to parentless widgets

        * gladeui/glade-property.h:
          Added a return value to glade_property_set* functions to indicate
          success/failure that is used in glade-command

        * gladeui/glade-property.c:
          Ignoring parentless_widget properties while duplicating properties.
          Additional check while adding/removing property reference
          Added a return value to glade_property_set* functions to indicate
          success/failure that is used in glade-command.
          Determining that property is changed using glade-proproperty method
          instead of direct comparing GValue.
          Loading properties through glade-widget-adaptor interface instead of
          getting them directly.
          remove_object method now unsets referencing property instead of
          setting it.
          Removed dummy duplicated setting of property while unsetting
          referencing property.

        * gladeui/glade-property.h:
          Added a return value to glade_property_set* functions to indicate
          success/failure that is used in glade-command.

        * gladeui/glade-widget.c:
          Removed setting widget properties to template/default values while
          building a new object, because they will be set later in constructor.
          Reloading properties after duplicating a widget.
          A new function for removing parent reference, that was made by setting
          parentless_widget property to the widget.
          Saving and loading parentless_widget properties while rebuilding,
          because they cannot be duplicated.
          Corrected destroying of an old widget while rebuilding. Seems like
          it's not fully correct still.

        * gladeui/glade-widget.h:
          A new function for removing parent reference, that was made by setting
          parentless_widget property to the widget.

        * gladeui/glade-xml-utils.h:
          A new tag "parentless-widget" as a property attribute

        * plugins/gtk+/glade-gtk.c, plugins/gtk+/gtk+.xml.in:
          Removed an old hack for "image" property of GtkMessageDialog.
          A new implementation of "image" property using parentless_widget
          kind of property.
          Added an ability of working with parentless widgets using
          "remove parent" and "add parent" items of context menu



Modified:
   trunk/ChangeLog
   trunk/gladeui/glade-app.c
   trunk/gladeui/glade-command.c
   trunk/gladeui/glade-command.h
   trunk/gladeui/glade-editor-property.c
   trunk/gladeui/glade-inspector.c
   trunk/gladeui/glade-palette.c
   trunk/gladeui/glade-palette.h
   trunk/gladeui/glade-placeholder.c
   trunk/gladeui/glade-placeholder.h
   trunk/gladeui/glade-popup.c
   trunk/gladeui/glade-popup.h
   trunk/gladeui/glade-project.c
   trunk/gladeui/glade-property-class.c
   trunk/gladeui/glade-property-class.h
   trunk/gladeui/glade-property.c
   trunk/gladeui/glade-property.h
   trunk/gladeui/glade-widget.c
   trunk/gladeui/glade-widget.h
   trunk/gladeui/glade-xml-utils.h
   trunk/plugins/gtk+/glade-gtk.c
   trunk/plugins/gtk+/gtk+.xml.in

Modified: trunk/gladeui/glade-app.c
==============================================================================
--- trunk/gladeui/glade-app.c	(original)
+++ trunk/gladeui/glade-app.c	Tue Sep 16 18:25:52 2008
@@ -300,7 +300,7 @@
 	/* class may be NULL if the selector was pressed */
 	if (adaptor && GWA_IS_TOPLEVEL (adaptor))
 	{
-		widget = glade_command_create (adaptor, NULL, NULL, app->priv->active_project);
+		widget = glade_palette_create_root_widget (palette, adaptor);
 		
 		/* if this is a top level widget set the accel group */
 		if (widget && app->priv->accel_group && GTK_IS_WINDOW (widget->object))
@@ -308,8 +308,6 @@
 			gtk_window_add_accel_group (GTK_WINDOW (widget->object),
 						    app->priv->accel_group);
 		}
-
-		glade_palette_deselect_current_item (palette, FALSE);
 	}
 }
 
@@ -1296,18 +1294,6 @@
 			if (glade_widget_placeholder_relation (parent, widget))
 				placeholder_relations++;
 		}
-
-		/* Check if there is no parent and at least on of the pasted
-		 * widgets is not a toplevel 
-		 */
-		else if (!GWA_IS_TOPLEVEL (widget->adaptor) && !parent)
-		{
-			glade_util_ui_message (glade_app_get_window (),
-					       GLADE_UI_INFO, NULL, 
-					       _("Unable to paste widget %s without a parent"),
-					       widget->name);
-			return;
-		}
 	}
 
 	g_assert (widget);

Modified: trunk/gladeui/glade-command.c
==============================================================================
--- trunk/gladeui/glade-command.c	(original)
+++ trunk/gladeui/glade-command.c	Tue Sep 16 18:25:52 2008
@@ -293,6 +293,12 @@
 			    G_GNUC_PRETTY_FUNCTION);
 }
 
+gint
+glade_command_get_group_depth (void)
+{
+	return gc_group_depth;
+}
+
 static void
 glade_command_check_group (GladeCommand *cmd)
 {
@@ -343,6 +349,8 @@
 {
 	GladeCommandSetProperty* me = (GladeCommandSetProperty*) cmd;
 	GList *l;
+	gboolean success;
+	gboolean retval = FALSE;
 
 	g_return_val_if_fail (me != NULL, FALSE);
 
@@ -395,9 +403,10 @@
 			}
 		}
 
-		glade_property_set_value (sdata->property, &new_value);
+		success = glade_property_set_value (sdata->property, &new_value);
+		retval = retval || success;
 
-		if (!me->set_once)
+		if (!me->set_once && success)
 		{
 			/* If some verify functions didnt pass on 
 			 * the first go.. we need to record the actual
@@ -419,7 +428,7 @@
 	me->set_once = TRUE;
 	me->undo     = !me->undo;
 
-	return TRUE;
+	return retval;
 }
 
 static void
@@ -458,6 +467,27 @@
        GCSetPropData           *pdata1, *pdata2;
        GList                   *list, *l;
 
+	if (!other_cmd)
+	{
+		if (GLADE_IS_COMMAND_SET_PROPERTY (this_cmd))
+		{
+			cmd1 = (GladeCommandSetProperty*) this_cmd;
+			
+			for (list = cmd1->sdata; list; list = list->next)
+			{
+				pdata1 = list->data;
+
+				if (glade_property_class_compare (pdata1->property->klass,
+								  pdata1->old_value,
+								  pdata1->new_value))
+					return FALSE;
+			}
+			return TRUE;
+				
+		}
+		return FALSE;
+	}
+
        if (GLADE_IS_COMMAND_SET_PROPERTY (this_cmd) && 
 	   GLADE_IS_COMMAND_SET_PROPERTY (other_cmd))
        {
@@ -579,6 +609,7 @@
 	GladeCommand  *cmd;
 	GCSetPropData *sdata;
 	GList         *list;
+	gboolean       success;
 
 	g_return_if_fail (GLADE_IS_PROJECT (project));
 	g_return_if_fail (props);
@@ -594,12 +625,17 @@
 	}
 
 	me->sdata        = props;
-	cmd->description = glade_command_set_property_description (me);
+	cmd->description = NULL;
 
+	glade_command_push_group (glade_command_set_property_description (me));
 	glade_command_check_group (GLADE_COMMAND (me));
 
 	/* Push onto undo stack only if it executes successfully. */
-	if (glade_command_set_property_execute (GLADE_COMMAND (me)))
+	success = glade_command_set_property_execute (GLADE_COMMAND (me));
+
+	glade_command_pop_group ();
+	
+	if (success)
 		glade_project_push_undo (GLADE_PROJECT (project),
 					 GLADE_COMMAND (me));
 	else
@@ -932,7 +968,7 @@
 		else if (GTK_IS_WINDOW (widget->object) == FALSE)
 			cdata->parent = parent;
 		if (cdata->parent == NULL && GTK_IS_WINDOW (widget->object) == FALSE)
-			g_critical ("Parentless non GtkWindow widget in Add");
+			g_message ("Parentless non GtkWindow widget in Add");
 
 		/* Placeholder */
 		if (placeholder != NULL && g_list_length (widgets) == 1)
@@ -1237,7 +1273,7 @@
 
 			/* Toplevels get pasted to the active project */
 			if (me->from_clipboard && 
-			    GTK_WIDGET_TOPLEVEL (cdata->widget->object))
+			    cdata->widget->parent == NULL)
 				glade_project_add_object 
 					(active_project, cdata->project,
 					 cdata->widget->object);
@@ -1560,8 +1596,6 @@
 	
 	g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL);
 	g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
-	if (GWA_IS_TOPLEVEL(adaptor) == FALSE)
-		g_return_val_if_fail (GLADE_IS_WIDGET(parent), NULL);
 		
 	/* attempt to create the widget -- widget may be null, e.g. the user clicked cancel on a query */
 	widget = glade_widget_adaptor_create_widget(adaptor, TRUE, "parent", parent, "project", project, NULL);

Modified: trunk/gladeui/glade-command.h
==============================================================================
--- trunk/gladeui/glade-command.h	(original)
+++ trunk/gladeui/glade-command.h	Tue Sep 16 18:25:52 2008
@@ -72,6 +72,8 @@
 
 void           glade_command_pop_group     (void);
 
+gint           glade_command_get_group_depth (void);
+
 
 gboolean       glade_command_execute       (GladeCommand      *command);
 

Modified: trunk/gladeui/glade-editor-property.c
==============================================================================
--- trunk/gladeui/glade-editor-property.c	(original)
+++ trunk/gladeui/glade-editor-property.c	Tue Sep 16 18:25:52 2008
@@ -2345,7 +2345,8 @@
 glade_eprop_object_populate_view_real (GladeEditorProperty *eprop,
 				       GtkTreeStore        *model,
 				       GList               *widgets,
-				       GtkTreeIter         *parent_iter)
+				       GtkTreeIter         *parent_iter,
+				       gboolean             recurse)
 {
 	GList *children, *list;
 	GtkTreeIter       iter;
@@ -2360,7 +2361,7 @@
 
 			if (GLADE_IS_PARAM_SPEC_OBJECTS (eprop->klass->pspec))
 			{
-				has_decendant = glade_widget_has_decendant 
+				has_decendant = recurse && glade_widget_has_decendant 
 					(widget, 
 					 glade_param_spec_objects_get_type 
 					 (GLADE_PARAM_SPEC_OBJECTS(eprop->klass->pspec)));
@@ -2377,14 +2378,17 @@
 			}
 			else
 			{
-				has_decendant = glade_widget_has_decendant 
+				has_decendant = recurse && glade_widget_has_decendant 
 					(widget, eprop->klass->pspec->value_type);
 
 				good_type = g_type_is_a (widget->adaptor->type, 
 							 eprop->klass->pspec->value_type);
 
 			}
-			
+
+			if (eprop->klass->parentless_widget)
+				good_type = good_type && !GWA_IS_TOPLEVEL (widget->adaptor);
+
 			if (good_type || has_decendant)
 			{
 				gtk_tree_store_append (model, &iter, parent_iter);
@@ -2412,7 +2416,7 @@
 				GtkTreeIter *copy = NULL;
 
 				copy = gtk_tree_iter_copy (&iter);
-				glade_eprop_object_populate_view_real (eprop, model, children, copy);
+				glade_eprop_object_populate_view_real (eprop, model, children, copy, recurse);
 				gtk_tree_iter_free (copy);
 
 				g_list_free (children);
@@ -2441,7 +2445,7 @@
 	}
 
 	/* add the widgets and recurse */
-	glade_eprop_object_populate_view_real (eprop, model, toplevels, NULL);
+	glade_eprop_object_populate_view_real (eprop, model, toplevels, NULL, !eprop->klass->parentless_widget);
 	g_list_free (toplevels);
 }
 
@@ -2698,7 +2702,38 @@
 			GValue *value = glade_property_class_make_gvalue_from_string
 				(eprop->klass, selected->name, project);
 
-			glade_editor_property_commit (eprop, value);
+			/* Unparent the widget so we can reuse it for this property */
+			if (eprop->klass->parentless_widget)
+			{
+				GObject *new_object, *old_object = NULL;
+				GladeWidget *new_widget;
+				GladeProperty *old_ref;
+
+				if (!G_IS_PARAM_SPEC_OBJECT (eprop->klass->pspec))
+					g_warning ("Parentless widget property should be of object type");
+				else
+				{
+					glade_property_get (eprop->property, &old_object);
+					new_object = g_value_get_object (value);
+					new_widget = glade_widget_get_from_gobject (new_object);
+
+					if (new_object && old_object != new_object &&
+					    (old_ref = glade_widget_get_parentless_widget_ref (new_widget)))
+					{
+						gchar *desc = g_strdup_printf (_("Setting %s of %s to %s"),
+									       eprop->property->klass->name,
+									       eprop->property->widget->name, 
+									       new_widget->name);
+						glade_command_push_group (desc);
+						glade_command_set_property (old_ref, NULL);
+						glade_editor_property_commit (eprop, value);
+						glade_command_pop_group ();
+						g_free (desc);
+					}
+				}
+			} 
+			else
+				glade_editor_property_commit (eprop, value);
 
 			g_value_unset (value);
 			g_free (value);

Modified: trunk/gladeui/glade-inspector.c
==============================================================================
--- trunk/gladeui/glade-inspector.c	(original)
+++ trunk/gladeui/glade-inspector.c	Tue Sep 16 18:25:52 2008
@@ -521,27 +521,31 @@
 	GtkTreePath      *path      = NULL;
 	gboolean          handled   = FALSE;
 
-	if (event->window == gtk_tree_view_get_bin_window (view) &&
-	    gtk_tree_view_get_path_at_pos (view, (gint) event->x, (gint) event->y,
+	if (event->window == gtk_tree_view_get_bin_window (view))
+	{
+		if (gtk_tree_view_get_path_at_pos (view, (gint) event->x, (gint) event->y,
 					   &path, NULL, 
 					   NULL, NULL) && path != NULL)
-	{
-		GtkTreeIter  iter;
-		GladeWidget *widget = NULL;
-		if (gtk_tree_model_get_iter (GTK_TREE_MODEL (inspector->priv->model),
-					     &iter, path))
 		{
-			/* now we can obtain the widget from the iter.
-			 */
-			gtk_tree_model_get (GTK_TREE_MODEL (inspector->priv->model), &iter,
-					    WIDGET_COLUMN, &widget, -1);
-			if (widget != NULL && event->button == 3)
+			GtkTreeIter  iter;
+			GladeWidget *widget = NULL;
+			if (gtk_tree_model_get_iter (GTK_TREE_MODEL (inspector->priv->model),
+							 &iter, path))
 			{
-				glade_popup_widget_pop (widget, event, FALSE);
-				handled = TRUE;
+				/* now we can obtain the widget from the iter.
+				 */
+				gtk_tree_model_get (GTK_TREE_MODEL (inspector->priv->model), &iter,
+							WIDGET_COLUMN, &widget, -1);
+				if (widget != NULL && event->button == 3)
+				{
+					glade_popup_widget_pop (widget, event, FALSE);
+					handled = TRUE;
+				}
+				gtk_tree_path_free (path);
 			}
-			gtk_tree_path_free (path);
 		}
+		else
+			glade_popup_simple_pop (event);
 	}
 	return handled;
 }

Modified: trunk/gladeui/glade-palette.c
==============================================================================
--- trunk/gladeui/glade-palette.c	(original)
+++ trunk/gladeui/glade-palette.c	Tue Sep 16 18:25:52 2008
@@ -62,6 +62,7 @@
 
 	GtkWidget    *selector_hbox;	
 	GtkWidget    *selector_button;
+	GtkWidget    *create_root_button;
 
 	GtkWidget    *tray;	         /* Where all the item groups are contained */
 
@@ -391,17 +392,42 @@
 	g_type_class_add_private (object_class, sizeof (GladePalettePrivate));
 }
 
+GladeWidget *
+glade_palette_create_root_widget (GladePalette *palette, GladeWidgetAdaptor *adaptor)
+{
+	GladeWidget *widget;
+	
+	widget = glade_command_create (adaptor, NULL, NULL, glade_app_get_project ());
+	
+	glade_palette_deselect_current_item (palette, FALSE);
+	
+	return widget;
+}
+
 static void
 glade_palette_on_button_toggled (GtkWidget *button, GladePalette *palette)
 {
 	GladePalettePrivate *priv;
 	GdkModifierType mask;
 	GladeWidgetAdaptor *adaptor;
+	gboolean is_root_active;
 	
 	g_return_if_fail (GLADE_IS_PALETTE (palette));
 	g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
 	priv = GLADE_PALETTE_GET_PRIVATE (palette);
 
+	is_root_active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->create_root_button));
+	
+	if (button == priv->create_root_button && priv->current_item && is_root_active)
+	{
+		adaptor = glade_palette_get_current_item (palette);
+		glade_palette_create_root_widget (palette, adaptor);
+		return;
+	}
+	
+	if (!GLADE_IS_PALETTE_ITEM (button))
+		return;
+
 	/* if we are toggling currently active item into non-active state */
 	if (priv->current_item == GLADE_PALETTE_ITEM (button))
 	{
@@ -427,6 +453,14 @@
 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->current_item), FALSE);
 		
 	priv->current_item = GLADE_PALETTE_ITEM (button);
+	
+	if (is_root_active)
+	{
+		adaptor = glade_palette_item_get_adaptor (GLADE_PALETTE_ITEM (button));
+		glade_palette_create_root_widget (palette, adaptor);
+		return;
+	}
+	
 	g_object_notify (G_OBJECT (palette), "current-item");
 
 	glade_app_set_pointer_mode (GLADE_POINTER_ADD_WIDGET);
@@ -586,6 +620,24 @@
 	return selector;
 }
 
+static GtkWidget* 
+glade_palette_create_create_root_button (GladePalette *palette)
+{	
+	GtkWidget *create_root_button;
+	
+	create_root_button = gtk_toggle_button_new ();
+	
+	gtk_container_set_border_width (GTK_CONTAINER (create_root_button), 0);
+	gtk_button_set_use_stock (GTK_BUTTON (create_root_button), TRUE);
+	gtk_button_set_label (GTK_BUTTON (create_root_button), "gtk-add");
+	
+	g_signal_connect (G_OBJECT (create_root_button), "toggled",
+			  G_CALLBACK (glade_palette_on_button_toggled), 
+			  palette);
+	
+	return create_root_button;
+}
+
 static void
 glade_palette_init (GladePalette *palette)
 {
@@ -604,12 +656,16 @@
 	/* create selector button */
 	priv->selector_button = glade_palette_create_selector_button (palette);
 	priv->selector_hbox = gtk_hbox_new (FALSE, 0);
+	priv->create_root_button = glade_palette_create_create_root_button (palette);
 	gtk_box_pack_start (GTK_BOX (priv->selector_hbox), priv->selector_button, FALSE, FALSE, 0);
+	gtk_box_pack_start (GTK_BOX (priv->selector_hbox), priv->create_root_button, FALSE, FALSE, 0);
 	gtk_box_pack_start (GTK_BOX (palette), priv->selector_hbox, FALSE, FALSE, 0);
 	gtk_widget_show (priv->selector_button);
+	gtk_widget_show (priv->create_root_button);
 	gtk_widget_show (priv->selector_hbox);
 
-        gtk_widget_set_tooltip_text (priv->selector_button, _("Widget selector"));
+	gtk_widget_set_tooltip_text (priv->selector_button, _("Widget selector"));
+	gtk_widget_set_tooltip_text (priv->create_root_button, _("Create root widget"));
 
 	/* create size group */
 	priv->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
@@ -703,8 +759,9 @@
 	if (palette->priv->current_item)
 	{
 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (palette->priv->current_item), FALSE);
-		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (palette->priv->selector_button), TRUE);		
-		
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (palette->priv->selector_button), TRUE);
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (palette->priv->create_root_button), FALSE);
+	
 		palette->priv->current_item = NULL;
 		g_object_notify (G_OBJECT (palette), "current-item");
 

Modified: trunk/gladeui/glade-palette.h
==============================================================================
--- trunk/gladeui/glade-palette.h	(original)
+++ trunk/gladeui/glade-palette.h	Tue Sep 16 18:25:52 2008
@@ -94,6 +94,9 @@
 
 void                 glade_palette_refresh                  (GladePalette *palette);
 
+GladeWidget         *glade_palette_create_root_widget       (GladePalette *palette,
+							     GladeWidgetAdaptor *adaptor);
+
 G_END_DECLS
 
 #endif /* __GLADE_PALETTE_H__ */

Modified: trunk/gladeui/glade-placeholder.c
==============================================================================
--- trunk/gladeui/glade-placeholder.c	(original)
+++ trunk/gladeui/glade-placeholder.c	Tue Sep 16 18:25:52 2008
@@ -259,7 +259,7 @@
 	gdk_event_free (event);
 }
 
-static GladeProject*
+GladeProject*
 glade_placeholder_get_project (GladePlaceholder *placeholder)
 {
 	GladeWidget *parent;

Modified: trunk/gladeui/glade-placeholder.h
==============================================================================
--- trunk/gladeui/glade-placeholder.h	(original)
+++ trunk/gladeui/glade-placeholder.h	Tue Sep 16 18:25:52 2008
@@ -25,6 +25,7 @@
 #define __GLADE_PLACEHOLDER_H__
 
 #include <gladeui/glade-widget.h>
+#include <gladeui/glade-project.h>
 #include <gtk/gtk.h>
 
 G_BEGIN_DECLS
@@ -58,6 +59,8 @@
 
 GtkWidget   *glade_placeholder_new        (void);
 
+GladeProject* glade_placeholder_get_project (GladePlaceholder *placeholder);
+
 GladeWidget *glade_placeholder_get_parent (GladePlaceholder *placeholder);
 
 G_END_DECLS

Modified: trunk/gladeui/glade-popup.c
==============================================================================
--- trunk/gladeui/glade-popup.c	(original)
+++ trunk/gladeui/glade-popup.c	Tue Sep 16 18:25:52 2008
@@ -47,6 +47,64 @@
 		(glade_widget_get_object (widget), TRUE);
 }
 
+static GladePlaceholder *
+find_placeholder (GObject *object)
+{
+	GtkContainer *container;
+	GladePlaceholder *retval = NULL;
+	GtkWidget *child;
+	GList *c, *l;
+
+	if (!GTK_IS_CONTAINER (object))
+		return NULL;
+
+	container = GTK_CONTAINER (object);
+	
+	for (c = l = glade_util_container_get_all_children (container);
+	     l;
+	     l = g_list_next (l))
+	{
+		child = l->data;
+		
+		if (GLADE_IS_PLACEHOLDER (child))
+		{
+			retval = GLADE_PLACEHOLDER (child);
+			break;
+		}
+	}
+	
+	g_list_free (c);
+
+	return retval;
+}
+
+static void
+glade_popup_placeholder_add_cb (GtkMenuItem *item, GladePlaceholder *placeholder)
+{
+	GladeWidgetAdaptor *adaptor;
+	
+	adaptor = glade_palette_get_current_item (glade_app_get_palette ());
+	g_return_if_fail (adaptor != NULL);
+	
+	glade_command_create (adaptor, glade_placeholder_get_parent (placeholder),
+						  placeholder, glade_placeholder_get_project (placeholder));
+						  
+	glade_palette_deselect_current_item (glade_app_get_palette(), TRUE);
+}
+
+static void
+glade_popup_root_add_cb (GtkMenuItem *item, gpointer *user_data)
+{
+	GladeWidgetAdaptor *adaptor;
+	GladePalette *palette;
+	
+	palette = glade_app_get_palette ();
+	adaptor = glade_palette_get_current_item (palette);
+	g_return_if_fail (adaptor != NULL);
+	
+	glade_palette_create_root_widget (palette, adaptor);
+}
+
 static void
 glade_popup_cut_cb (GtkMenuItem *item, GladeWidget *widget)
 {
@@ -325,8 +383,35 @@
 {
 	GtkWidget *popup_menu;
 	gboolean   sensitive;
+	GladePlaceholder *tmp_placeholder;
+
+	sensitive = glade_palette_get_current_item (glade_app_get_palette ()) != NULL;
+
+	if (!sensitive && !widget)
+		return NULL;
 
 	popup_menu = gtk_menu_new ();
+	
+	if (sensitive)
+	{		
+		tmp_placeholder = placeholder;
+		if (!tmp_placeholder && widget)
+			tmp_placeholder = find_placeholder (glade_widget_get_object (widget));
+		glade_popup_append_item (popup_menu, NULL, _("_Add widget here"), tmp_placeholder != NULL,
+					 glade_popup_placeholder_add_cb, tmp_placeholder);
+		glade_popup_append_item (popup_menu, NULL, _("Add widget as _root"), TRUE,
+					 glade_popup_root_add_cb, NULL);
+	}
+
+	if (!widget)
+		return popup_menu;
+		
+	if (sensitive)
+	{
+		GtkWidget *separator = gtk_menu_item_new ();		
+		gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), separator);
+		gtk_widget_show (separator);
+	}
 
 	glade_popup_append_item (popup_menu, NULL, _("_Select"), TRUE,
 				 glade_popup_select_cb, widget);
@@ -418,7 +503,7 @@
 	gint button;
 	gint event_time;
 
-	g_return_if_fail (GLADE_IS_WIDGET (widget));
+	g_return_if_fail (GLADE_IS_WIDGET (widget) || widget == NULL);
 
 	popup_menu = glade_popup_create_menu (widget, NULL, packing);
 
@@ -492,3 +577,29 @@
 	gtk_menu_popup (GTK_MENU (popup_menu), NULL, NULL,
 			NULL, NULL, button, event_time);
 }
+
+void
+glade_popup_simple_pop (GdkEventButton *event)
+{
+	GtkWidget *popup_menu;
+	gint button;
+	gint event_time;
+	
+	popup_menu = glade_popup_create_menu (NULL, NULL, FALSE);
+	if (!popup_menu)
+		return;
+
+	if (event)
+	{
+		button = event->button;
+		event_time = event->time;
+	}
+	else
+	{
+		button = 0;
+		event_time = gtk_get_current_event_time ();
+	}
+	gtk_menu_popup (GTK_MENU (popup_menu), NULL, NULL,
+		NULL, NULL, button, event_time);
+}
+

Modified: trunk/gladeui/glade-popup.h
==============================================================================
--- trunk/gladeui/glade-popup.h	(original)
+++ trunk/gladeui/glade-popup.h	Tue Sep 16 18:25:52 2008
@@ -19,6 +19,9 @@
 				       GladeWidgetAction *action,
 				       gboolean packing);
 
+void
+glade_popup_simple_pop                (GdkEventButton *event);
+
 G_END_DECLS
 
 #endif /* __GLADE_POPUP_H__ */

Modified: trunk/gladeui/glade-project.c
==============================================================================
--- trunk/gladeui/glade-project.c	(original)
+++ trunk/gladeui/glade-project.c	Tue Sep 16 18:25:52 2008
@@ -387,43 +387,29 @@
 		return l->next ? GLADE_COMMAND (l->next->data) : NULL;
 }
 
+static GList *
+glade_project_free_undo_item (GladeProject *project, GList *item)
+{
+	g_assert (item->data);
+
+	if (item == project->priv->first_modification)
+		project->priv->first_modification_is_na = TRUE;
+
+	g_object_unref (G_OBJECT (item->data));
+
+	return g_list_next (item);
+}
+
 static void
 glade_project_push_undo_impl (GladeProject *project, GladeCommand *cmd)
 {
 	GladeProjectPrivate *priv = project->priv;
 	GList *tmp_redo_item;
 
-	/* If there are no "redo" items, and the last "undo" item unifies with
-	   us, then we collapse the two items in one and we're done */
-	if (priv->prev_redo_item != NULL && priv->prev_redo_item->next == NULL)
-	{
-		GladeCommand *cmd1 = priv->prev_redo_item->data;
-		
-		if (glade_command_unifies (cmd1, cmd))
-		{
-			glade_command_collapse (cmd1, cmd);
-			g_object_unref (cmd);
-
-			g_signal_emit (G_OBJECT (project),
-				       glade_project_signals [CHANGED],
-				       0, cmd1, TRUE);
-			return;
-		}
-	}
-
 	/* We should now free all the "redo" items */
 	tmp_redo_item = g_list_next (priv->prev_redo_item);
 	while (tmp_redo_item)
-	{
-		g_assert (tmp_redo_item->data);
-		
-		if (tmp_redo_item == priv->first_modification)
-			priv->first_modification_is_na = TRUE;
-		
-		g_object_unref (G_OBJECT (tmp_redo_item->data));
-		
-		tmp_redo_item = g_list_next (tmp_redo_item);
-	}
+		tmp_redo_item = glade_project_free_undo_item (project, tmp_redo_item);
 
 	if (priv->prev_redo_item)
 	{
@@ -436,6 +422,40 @@
 		priv->undo_stack = NULL;
 	}
 
+	/* Try to unify only if group depth is 0 */
+	if (glade_command_get_group_depth() == 0 &&
+	    priv->prev_redo_item != NULL)
+	{
+		GladeCommand *cmd1 = priv->prev_redo_item->data;
+		gboolean is_atomic = FALSE;
+
+		/* Cannot unify with a part of a command group.
+		 * Unify atomic commands only
+		 */
+		if (cmd1->group_id == 0 || cmd->group_id == 0 ||
+		    cmd->group_id != cmd1->group_id)
+			is_atomic = TRUE;
+
+		if (is_atomic && glade_command_unifies (cmd1, cmd))
+		{
+			glade_command_collapse (cmd1, cmd);
+			g_object_unref (cmd);
+
+			if (glade_command_unifies (cmd1, NULL))
+			{
+				tmp_redo_item = priv->prev_redo_item;
+				glade_project_walk_back (project);
+				glade_project_free_undo_item (project, tmp_redo_item);
+				priv->undo_stack = g_list_delete_link (priv->undo_stack, tmp_redo_item);
+			}
+
+			g_signal_emit (G_OBJECT (project),
+				       glade_project_signals [CHANGED],
+				       0, NULL, TRUE);
+			return;
+		}
+	}
+
 	/* and then push the new undo item */
 	priv->undo_stack = g_list_append (priv->undo_stack, cmd);
 

Modified: trunk/gladeui/glade-property-class.c
==============================================================================
--- trunk/gladeui/glade-property-class.c	(original)
+++ trunk/gladeui/glade-property-class.c	Tue Sep 16 18:25:52 2008
@@ -1497,6 +1497,7 @@
 	klass->weight      = glade_xml_get_property_double  (node, GLADE_TAG_WEIGHT,      klass->weight);
 	klass->transfer_on_paste = glade_xml_get_property_boolean (node, GLADE_TAG_TRANSFER_ON_PASTE, klass->transfer_on_paste);
 	klass->save_always = glade_xml_get_property_boolean (node, GLADE_TAG_SAVE_ALWAYS, klass->save_always);
+	klass->parentless_widget = glade_xml_get_property_boolean (node, GLADE_TAG_PARENTLESS_WIDGET, klass->parentless_widget);
 	
 
 	/* Special case pixbuf here.

Modified: trunk/gladeui/glade-property-class.h
==============================================================================
--- trunk/gladeui/glade-property-class.h	(original)
+++ trunk/gladeui/glade-property-class.h	Tue Sep 16 18:25:52 2008
@@ -159,7 +159,10 @@
 				  * will be used to lookup the theme by the
 				  * implementing widget
 				  */
-	
+
+	gboolean parentless_widget;  /* True if this property should point to a parentless widget
+				      * in the project
+				      */
 };
 
 

Modified: trunk/gladeui/glade-property.c
==============================================================================
--- trunk/gladeui/glade-property.c	(original)
+++ trunk/gladeui/glade-property.c	Tue Sep 16 18:25:52 2008
@@ -97,7 +97,16 @@
 	property->value   = g_new0 (GValue, 1);
 
 	g_value_init (property->value, template_prop->value->g_type);
-	g_value_copy (template_prop->value, property->value);
+	/* Cannot duplicate parentless_widget property */
+	if (template_prop->klass->parentless_widget)
+	{
+		if (!G_IS_PARAM_SPEC_OBJECT (template_prop->klass->pspec))
+			g_warning ("Parentless widget property should be of object type");
+
+		g_value_set_object (property->value, NULL);
+	}
+	else
+		g_value_copy (template_prop->value, property->value);
 
 	/* Need value in place here ... */
 	glade_property_set_enabled (property, template_prop->enabled);
@@ -142,13 +151,15 @@
 		{
 			old_object = list->data;
 			gold = glade_widget_get_from_gobject (old_object);
-			glade_widget_remove_prop_ref (gold, property);
+			if (gold != NULL)
+				glade_widget_remove_prop_ref (gold, property);
 		}
 		for (list = added; list; list = list->next)
 		{
 			new_object = list->data;
 			gnew = glade_widget_get_from_gobject (new_object);
-			glade_widget_add_prop_ref (gnew, property);
+			if (gnew != NULL)
+				glade_widget_add_prop_ref (gnew, property);
 		}
 
 		g_list_free (removed);
@@ -161,12 +172,14 @@
 		if ((old_object = g_value_get_object (old_value)) != NULL)
 		{
 			gold = glade_widget_get_from_gobject (old_object);
+			g_return_if_fail (gold != NULL);
 			glade_widget_remove_prop_ref (gold, property);
 		}
 		
 		if ((new_object = g_value_get_object (new_value)) != NULL)
 		{
 			gnew = glade_widget_get_from_gobject (new_object);
+			g_return_if_fail (gnew != NULL);
 			glade_widget_add_prop_ref (gnew, property);
 		}
 	}
@@ -227,7 +240,7 @@
 }
 
 
-static void
+static gboolean
 glade_property_set_value_impl (GladeProperty *property, const GValue *value)
 {
 	GladeProject *project = property->widget ?
@@ -251,7 +264,7 @@
 	{
 		g_warning ("Trying to assign an incompatible value to property %s\n",
 			    property->klass->id);
-		return;
+		return FALSE;
 	}
 
 	/* Check if the backend doesnt give us permission to
@@ -260,12 +273,13 @@
 	if (glade_property_superuser () == FALSE && property->widget &&
 	    project && glade_project_is_loading (project) == FALSE &&
 	    glade_property_verify (property, value) == FALSE)
-		return;
+	{
+		return FALSE;
+	}
 	
 	/* save "changed" state.
 	 */
-	changed = g_param_values_cmp (property->klass->pspec, 
-				      property->value, value) != 0;
+	changed = !glade_property_equals_value (property, value);
 
 
 	/* Add/Remove references from widget ref stacks here
@@ -299,6 +313,8 @@
 	}
 	
 	g_value_unset (&old_value);
+
+	return TRUE;
 }
 
 static void
@@ -374,7 +390,7 @@
 	oclass = G_OBJECT_GET_CLASS (object);
 	
 	if (g_object_class_find_property (oclass, property->klass->id))
-		g_object_get_property (object, property->klass->id, property->value);
+		glade_widget_object_get_property (property->widget, property->klass->id, property->value);
 }
 
 /*******************************************************************************
@@ -798,12 +814,12 @@
  *
  * Sets the property's value
  */
-void
+gboolean
 glade_property_set_value (GladeProperty *property, const GValue *value)
 {
-	g_return_if_fail (GLADE_IS_PROPERTY (property));
-	g_return_if_fail (value != NULL);
-	GLADE_PROPERTY_GET_KLASS (property)->set_value (property, value);
+	g_return_val_if_fail (GLADE_IS_PROPERTY (property), FALSE);
+	g_return_val_if_fail (value != NULL, FALSE);
+	return GLADE_PROPERTY_GET_KLASS (property)->set_value (property, value);
 }
 
 /**
@@ -813,19 +829,22 @@
  *
  * Sets the property's value
  */
-void
+gboolean
 glade_property_set_va_list (GladeProperty *property, va_list vl)
 {
 	GValue  *value;
+	gboolean success;
 
-	g_return_if_fail (GLADE_IS_PROPERTY (property));
+	g_return_val_if_fail (GLADE_IS_PROPERTY (property), FALSE);
 
 	value = glade_property_class_make_gvalue_from_vl (property->klass, vl);
 
-	GLADE_PROPERTY_GET_KLASS (property)->set_value (property, value);
-	
+	success = GLADE_PROPERTY_GET_KLASS (property)->set_value (property, value);
+
 	g_value_unset (value);
 	g_free (value);
+
+	return success;
 }
 
 /**
@@ -835,16 +854,19 @@
  *
  * Sets the property's value (in a convenient way)
  */
-void
+gboolean
 glade_property_set (GladeProperty *property, ...)
 {
 	va_list  vl;
+	gboolean success;
 
-	g_return_if_fail (GLADE_IS_PROPERTY (property));
+	g_return_val_if_fail (GLADE_IS_PROPERTY (property), FALSE);
 
 	va_start (vl, property);
-	glade_property_set_va_list (property, vl);
+	success = glade_property_set_va_list (property, vl);
 	va_end (vl);
+
+	return success;
 }
 
 /**
@@ -1286,14 +1308,8 @@
 	}
 	else
 	{
-		glade_property_set (property, object);
+		glade_property_set (property, NULL);
 	}
-
-	glade_property_class_get_from_gvalue (property->klass,
-					      property->value,
-					      &list);
-
-	glade_property_set (property, list);
 }
 
 /* Parameters for translatable properties. */

Modified: trunk/gladeui/glade-property.h
==============================================================================
--- trunk/gladeui/glade-property.h	(original)
+++ trunk/gladeui/glade-property.h	Tue Sep 16 18:25:52 2008
@@ -91,7 +91,7 @@
 	/* Class methods */
 	GladeProperty *         (* dup)                   (GladeProperty *, GladeWidget *);
 	gboolean                (* equals_value)          (GladeProperty *, const GValue *);
-	void                    (* set_value)             (GladeProperty *, const GValue *);
+	gboolean                (* set_value)             (GladeProperty *, const GValue *);
 	void                    (* get_value)             (GladeProperty *, GValue *);
 	void                    (* get_default)           (GladeProperty *, GValue *);
 	void                    (* sync)                  (GladeProperty *);
@@ -127,13 +127,13 @@
 gboolean                glade_property_equals                (GladeProperty      *property, 
 							      ...);
 
-void                    glade_property_set_value             (GladeProperty      *property, 
+gboolean                glade_property_set_value             (GladeProperty      *property, 
 							      const GValue       *value);
 
-void                    glade_property_set_va_list           (GladeProperty      *property,
+gboolean                glade_property_set_va_list           (GladeProperty      *property,
 							      va_list             vl);
 
-void                    glade_property_set                   (GladeProperty      *property,
+gboolean                glade_property_set                   (GladeProperty      *property,
 							      ...);
 
 void                    glade_property_get_value             (GladeProperty      *property, 

Modified: trunk/gladeui/glade-widget.c
==============================================================================
--- trunk/gladeui/glade-widget.c	(original)
+++ trunk/gladeui/glade-widget.c	Tue Sep 16 18:25:52 2008
@@ -508,7 +508,7 @@
 {
 	GParameter          *params;
 	GObject             *object;
-	guint                n_params, i;
+	guint                n_params;
 	
 	if (reason == GLADE_CREATE_LOAD)
 		return g_object_new (adaptor->type, NULL);
@@ -524,18 +524,6 @@
 
 	free_params (params, n_params);
 
-	if (widget)
-		params = glade_widget_template_params (widget, FALSE, &n_params);
-	else
-		params = glade_widget_adaptor_default_params (adaptor, FALSE, &n_params);
-
-	for (i = 0; i < n_params; i++)
-	{
-		g_object_set_property (object, params[i].name, &(params[i].value));
-	}
-
-	free_params (params, n_params);
-
 	return object;
 }
 
@@ -1301,9 +1289,10 @@
 {
 	GladeGetInternalFunc  get_internal;
 	GladeWidget *gwidget = NULL, *internal_parent;
-	GList       *list, *children;
+	GList       *children;
 	GtkWidget   *placeholder;
 	gchar       *child_type;
+	GList       *l;
 	
 	g_return_val_if_fail (template_widget != NULL && GLADE_IS_WIDGET(template_widget), NULL);
 	g_return_val_if_fail (parent == NULL || GLADE_IS_WIDGET (parent), NULL);
@@ -1351,6 +1340,8 @@
 	     glade_widget_adaptor_get_children (template_widget->adaptor,
 						template_widget->object)) != NULL)
 	{
+		GList       *list;
+
 		for (list = children; list && list->data; list = list->next)
 		{
 			GObject     *child = G_OBJECT (list->data);
@@ -1417,6 +1408,10 @@
 	 */
 	glade_widget_sync_custom_props (gwidget);
 
+	/* Some properties may not be synced so we reload them */
+	for (l = gwidget->properties; l; l = l->next)
+		glade_property_load (GLADE_PROPERTY (l->data));
+
 	/* Special case GtkWindow here and ensure the pasted window
 	 * has the same size as the 'Cut' one.
 	 */
@@ -1938,6 +1933,25 @@
 		widget->prop_refs = g_list_remove (widget->prop_refs, property);
 }
 
+GladeProperty *
+glade_widget_get_parentless_widget_ref (GladeWidget *widget)
+{
+	GList         *l;
+	GladeProperty *property;
+
+	g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
+
+	for (l = widget->prop_refs; l && l->data; l = l->next)
+	{
+		property = GLADE_PROPERTY (l->data);
+
+		if (property->klass->parentless_widget)
+			/* For now only one property can point to the widget */
+			return property;
+	}
+	return NULL;
+}
+
 /**
  * glade_widget_project_notify:
  * @widget: A #GladeWidget
@@ -2146,6 +2160,12 @@
 	return widget;
 }
 
+typedef struct
+{
+	gchar *name;
+	GValue value;
+} PropertyData;
+
 /**
  * glade_widget_rebuild:
  * @gwidget: a #GladeWidget
@@ -2162,6 +2182,8 @@
 	GladeWidgetAdaptor *adaptor;
 	GList              *children;
 	gboolean            reselect = FALSE, inproject;
+	GList              *npw_properties = NULL;
+	GList              *l;
 	
 	g_return_if_fail (GLADE_IS_WIDGET (gwidget));
 
@@ -2190,6 +2212,28 @@
 	/* Extract and keep the child hierarchies aside... */
 	children = glade_widget_extract_children (gwidget);
 
+	/* parentless_widget properties should be unset before transfering */
+	for (l = gwidget->properties; l; l = l->next)
+	{
+		GladeProperty *property = GLADE_PROPERTY (l->data);
+		if (property->klass->parentless_widget)
+		{
+			PropertyData *prop_data;
+
+			if (!G_IS_PARAM_SPEC_OBJECT (property->klass->pspec))
+				g_warning ("Parentless widget property should be of object type");
+
+			prop_data = g_new0 (PropertyData, 1);
+			prop_data->name = g_strdup (property->klass->id);
+			g_value_init (&prop_data->value, property->value->g_type);
+			g_value_copy (property->value, &prop_data->value);
+
+			npw_properties = g_list_prepend (npw_properties,
+							 prop_data);
+			glade_property_set (property, NULL);
+		}
+	}
+
 	/* Hold a reference to the old widget while we transport properties
 	 * and children from it
 	 */
@@ -2207,6 +2251,12 @@
 		glade_widget_replace (gwidget->parent,
 				      old_object, new_object);
 
+	/* Must call dispose for cases like dialogs and toplevels */
+	if (g_type_is_a (adaptor->type, GTK_TYPE_OBJECT))
+		gtk_object_destroy  (GTK_OBJECT (old_object));
+	else
+		g_object_run_dispose (G_OBJECT (old_object));
+
 	/* Reparent any children of the old object to the new object
 	 * (this function will consume and free the child list).
 	 */
@@ -2219,19 +2269,23 @@
 	 */
 	glade_widget_sync_custom_props (gwidget);
 
+	/* Setting parentless_widget properties back */
+	for (l = npw_properties; l; l = l->next)
+	{
+		PropertyData *prop_data = l->data;
+		GladeProperty *property = glade_widget_get_property (gwidget, prop_data->name);
+
+		glade_property_set_value (property, &prop_data->value);
+
+		g_value_unset (&prop_data->value);
+		g_free (prop_data->name);
+		g_free (prop_data);
+	}
+	npw_properties = NULL;
+
 	/* Sync packing.
 	 */
 	glade_widget_sync_packing_props (gwidget);
-	
-	if (g_type_is_a (adaptor->type, GTK_TYPE_WIDGET))
-	{
-		/* Must use gtk_widget_destroy here for cases like dialogs and toplevels
-		 * (otherwise I'd prefer g_object_unref() )
-		 */
-		gtk_widget_destroy  (GTK_WIDGET(old_object));
-	}
-	else
-		g_object_unref (old_object);
 
 	/* If the widget was in a project (and maybe the selection), then
 	 * restore that stuff.

Modified: trunk/gladeui/glade-widget.h
==============================================================================
--- trunk/gladeui/glade-widget.h	(original)
+++ trunk/gladeui/glade-widget.h	Tue Sep 16 18:25:52 2008
@@ -269,6 +269,8 @@
 void                    glade_widget_remove_prop_ref        (GladeWidget      *widget,
 							     GladeProperty    *property);
 
+GladeProperty          *glade_widget_get_parentless_widget_ref (GladeWidget  *widget);
+
 /*******************************************************************************
             Functions that deal with properties on the runtime object
  *******************************************************************************/

Modified: trunk/gladeui/glade-xml-utils.h
==============================================================================
--- trunk/gladeui/glade-xml-utils.h	(original)
+++ trunk/gladeui/glade-xml-utils.h	Tue Sep 16 18:25:52 2008
@@ -79,6 +79,7 @@
 #define GLADE_TAG_SIGNALS                         "signals"
 #define GLADE_TAG_SIGNAL                          "signal"
 #define GLADE_TAG_DEFAULT                         "default"
+#define GLADE_TAG_PARENTLESS_WIDGET               "parentless-widget"
 #define GLADE_TAG_DISABLED                        "disabled"
 #define GLADE_TAG_DEFAULT_PALETTE_STATE           "default-palette-state"
 #define GLADE_TAG_REPLACE_CHILD_FUNCTION          "replace-child-function"

Modified: trunk/plugins/gtk+/glade-gtk.c
==============================================================================
--- trunk/plugins/gtk+/glade-gtk.c	(original)
+++ trunk/plugins/gtk+/glade-gtk.c	Tue Sep 16 18:25:52 2008
@@ -1076,8 +1076,7 @@
 	if (!gwidget)
 		return;
 
-	if (gwidget->parent && !GTK_IS_WINDOW (glade_widget_get_object (gwidget->parent)) &&
-	    gwidget->parent->internal == NULL)
+	if (gwidget->parent && gwidget->parent->internal == NULL)
 		glade_widget_set_action_sensitive (gwidget, "remove_parent", TRUE);
 	else
 		glade_widget_set_action_sensitive (gwidget, "remove_parent", FALSE);
@@ -1171,18 +1170,17 @@
 	GList       this_widget = { 0, }, that_widget = { 0, };
 	GtkWidget   *parent = GTK_WIDGET (object)->parent;
 
-	g_assert (parent);
+	if (parent)
+		gparent = glade_widget_get_from_gobject (parent);
+	else
+		gparent = NULL;
 
-	gparent = glade_widget_get_from_gobject (parent);
-	
 	if (strcmp (action_path, "remove_parent") == 0)
 	{
-		GladeWidget *new_gparent = gparent->parent;
+		GladeWidget *new_gparent;
 
-		/* Since toplevel project objects for now must be GtkWindow,
-		 * we'll just assert this for now (should be an insensitive action).
-		 */
-		g_assert (!GTK_IS_WINDOW (parent));
+		g_return_if_fail (gparent);
+		new_gparent = gparent->parent;
 		
 		glade_command_push_group (_("Removing parent of %s"), 
 					  gwidget->name);
@@ -1234,8 +1232,9 @@
 		{
 			GladeWidgetAdaptor *adaptor = glade_widget_adaptor_get_by_type (new_type);
 			GList              *saved_props, *prop_cmds;
+			GladeProject       *project;
 			
-			glade_command_push_group (_("Adding parent %s to %s"), 
+			glade_command_push_group (_("Adding parent %s for %s"), 
 						  adaptor->title, gwidget->name);
 
 			/* Record packing properties */
@@ -1244,11 +1243,15 @@
 			/* Remove "this" widget */
 			this_widget.data = gwidget;
 			glade_command_cut (&this_widget);
-			
+
+			if (gparent)
+				project = glade_widget_get_project (gparent);
+			else
+				project = glade_app_get_project ();
 			/* Create new widget and put it where the placeholder was */
 			that_widget.data =
 				glade_command_create (adaptor, gparent, NULL, 
-						      glade_widget_get_project (gparent));
+						      project);
 
 
 			/* Remove the alignment that we added in the frame's post_create... */
@@ -4859,27 +4862,6 @@
 	return list;
 }
 
-
-void
-glade_gtk_dialog_set_property (GladeWidgetAdaptor *adaptor,
-			       GObject            *object, 
-			       const gchar        *id,
-			       const GValue       *value)
-{
-	if (GTK_IS_MESSAGE_DIALOG (object) && !strcmp (id, "image"))
-	{
-		/* Gtk+ 2.10 crashes when you unset the image of 
-		 * a message dialog, so we dont ever unset it.
-		 */
-		if (g_value_get_object (value))
-			gtk_message_dialog_set_image (GTK_MESSAGE_DIALOG (object),
-						      GTK_WIDGET (g_value_get_object (value)));
-	}
-	else
-		GWA_GET_CLASS (GTK_TYPE_WINDOW)->set_property (adaptor, object,
-							       id, value);
-}
-
 /* ----------------------------- GtkFileChooserWidget ------------------------------ */
 void
 glade_gtk_file_chooser_widget_post_create (GladeWidgetAdaptor *adaptor,
@@ -8052,3 +8034,177 @@
 							     property_name, 
 							     value);
 }
+
+/*--------------------------- GtkMessageDialog ---------------------------------*/
+static gboolean
+glade_gtk_message_dialog_reset_image (GtkMessageDialog *dialog)
+{
+	gint message_type;
+
+	g_object_get (dialog, "message-type", &message_type, NULL);
+	if (message_type != GTK_MESSAGE_OTHER)
+		return FALSE;
+
+	if (glade_widget_get_from_gobject (dialog->image))
+	{
+		gtk_message_dialog_set_image (dialog,
+					      gtk_image_new_from_stock (NULL, GTK_ICON_SIZE_DIALOG));
+		gtk_widget_show (dialog->image);
+
+		return TRUE;
+	}
+	else
+		return FALSE;
+}
+
+enum {
+	MD_IMAGE_ACTION_INVALID,
+	MD_IMAGE_ACTION_RESET,
+	MD_IMAGE_ACTION_SET
+};
+
+static gint
+glade_gtk_message_dialog_image_determine_action (GtkMessageDialog *dialog,
+					   const GValue *value,
+					   GtkWidget **image,
+					   GladeWidget **gimage)
+{
+	*image = g_value_get_object (value);
+	
+	if (*image == NULL)
+		if (glade_widget_get_from_gobject (dialog->image))
+			return MD_IMAGE_ACTION_RESET;
+		else
+			return MD_IMAGE_ACTION_INVALID;
+	else
+	{
+		*image = GTK_WIDGET (*image);
+		if (dialog->image == *image)
+			return MD_IMAGE_ACTION_INVALID;
+		if (gtk_widget_get_parent (*image))
+			return MD_IMAGE_ACTION_INVALID;
+			
+		*gimage = glade_widget_get_from_gobject (*image);
+
+		if (!*gimage)
+		{
+			g_warning ("Setting property to an object outside the project");
+			return MD_IMAGE_ACTION_INVALID;
+		}
+		
+		if (glade_widget_get_parent (*gimage) || GTK_IS_WINDOW (*image))
+			return MD_IMAGE_ACTION_INVALID;
+
+		return MD_IMAGE_ACTION_SET;
+	}
+}
+
+void
+glade_gtk_message_dialog_set_property (GladeWidgetAdaptor *adaptor,
+			       GObject            *object,
+			       const gchar        *id,
+			       const GValue       *value)
+{
+	GtkMessageDialog *dialog = GTK_MESSAGE_DIALOG (object);
+	GladeWidget *gwidget = glade_widget_get_from_gobject (object);
+
+	g_return_if_fail (gwidget);
+
+	if (strcmp (id, "image") == 0)
+	{
+		GtkWidget *image = NULL;
+		GladeWidget *gimage = NULL;
+		gint rslt;
+
+		rslt = glade_gtk_message_dialog_image_determine_action (dialog, value,
+								       &image, &gimage);
+		switch (rslt)
+		{
+		case MD_IMAGE_ACTION_INVALID:
+			return;
+		case MD_IMAGE_ACTION_RESET:
+			glade_gtk_message_dialog_reset_image (dialog);
+			return;
+		case MD_IMAGE_ACTION_SET:
+			break; /* continue setting the property */
+		}
+
+		if (gtk_widget_get_parent (image))
+			g_critical ("Image should have no parent now");
+
+		gtk_message_dialog_set_image (dialog, image);
+
+		{
+			/* syncing "message-type" property */	
+			GladeProperty *property;
+
+			property = glade_widget_get_property (gwidget, "message-type");
+			if (!glade_property_equals (property, GTK_MESSAGE_OTHER))
+				glade_command_set_property (property, GTK_MESSAGE_OTHER);
+		}
+	}
+	else
+	{
+		/* We must reset the image to internal,
+		 * external image would otherwise become internal
+		 */
+		if (!strcmp (id, "message-type") &&
+		    g_value_get_enum (value) != GTK_MESSAGE_OTHER)
+		{
+			GladeProperty *property;
+
+			property = glade_widget_get_property (gwidget, "image");
+			if (!glade_property_equals (property, NULL))
+				glade_command_set_property (property, NULL);
+		}
+		/* Chain up, even if property us message-type because
+		 * it's not fully handled here
+		 */
+		GWA_GET_CLASS (GTK_TYPE_DIALOG)->set_property (adaptor, object,
+								  id, value);
+	}
+}
+
+gboolean
+glade_gtk_message_dialog_verify_property (GladeWidgetAdaptor *adaptor,
+				 GObject            *object,
+				 const gchar        *id,
+				 const GValue       *value)
+{
+	if (!strcmp (id, "image"))
+	{
+		GtkWidget *image; GladeWidget *gimage;
+
+		gboolean retval = MD_IMAGE_ACTION_INVALID != 
+		       glade_gtk_message_dialog_image_determine_action (GTK_MESSAGE_DIALOG (object),
+									value, &image, &gimage);
+
+		return retval;
+	}
+	else
+		if (GWA_GET_CLASS (GTK_TYPE_CONTAINER)->verify_property)
+			return GWA_GET_CLASS (GTK_TYPE_CONTAINER)->verify_property (adaptor, object,
+										    id, value);
+		else
+			return TRUE;
+}
+
+void
+glade_gtk_message_dialog_get_property (GladeWidgetAdaptor *adaptor,
+				  GObject *object,
+				  const gchar *property_name,
+				  GValue *value)
+{
+	if (!strcmp (property_name, "image"))
+	{
+		GtkMessageDialog *dialog = GTK_MESSAGE_DIALOG (object);
+
+		if (!glade_widget_get_from_gobject (dialog->image))
+			g_value_set_object (value, NULL);
+		else
+			g_value_set_object (value, dialog->image);
+	}
+	else
+		GWA_GET_CLASS (GTK_TYPE_DIALOG)->get_property (adaptor, object,
+								  property_name, value);
+}

Modified: trunk/plugins/gtk+/gtk+.xml.in
==============================================================================
--- trunk/plugins/gtk+/gtk+.xml.in	(original)
+++ trunk/plugins/gtk+/gtk+.xml.in	Tue Sep 16 18:25:52 2008
@@ -1022,7 +1022,6 @@
       <post-create-function>glade_gtk_dialog_post_create</post-create-function>
       <get-internal-child-function>glade_gtk_dialog_get_internal_child</get-internal-child-function>
       <get-children-function>glade_gtk_dialog_get_children</get-children-function>
-      <set-property-function>glade_gtk_dialog_set_property</set-property-function>
       <properties>
 	<property id="default-width"  default="320" optional="True" optional-default="False"/>
 	<property id="default-height" default="260" optional="True" optional-default="False"/>
@@ -1489,6 +1488,10 @@
     </glade-widget-class>
     
     <glade-widget-class name="GtkMessageDialog" generic-name="messagedialog" _title="Message Dialog" default-width="400" default-height="115">
+      <set-property-function>glade_gtk_message_dialog_set_property</set-property-function>
+      <get-property-function>glade_gtk_message_dialog_get_property</get-property-function>
+      <verify-function>glade_gtk_message_dialog_verify_property</verify-function>
+
       <properties>
 	<property id="default-width"  default="400" optional="True" optional-default="False"/>
 	<property id="default-height" default="115" optional="True" optional-default="False"/>
@@ -1498,7 +1501,7 @@
 	<property common="True" id="has-default"/>
 	<property common="True" id="can-focus"/>
 
-	<property id="image" since="2.10"/>
+	<property id="image" since="2.10" parentless-widget="True"/>
 	<property id="secondary-text" since="2.10"/>
 	<property id="secondary-use-markup" since="2.10"/>
 	<property id="text" since="2.10"/>



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