[glade] Created GladeProjectProperties dialog



commit 92592e15179c3cda2ed44fc1ef7ad6b28d611b4a
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date:   Sat Apr 20 17:06:42 2013 +0900

    Created GladeProjectProperties dialog
    
    Split out the code in GladeProject and created a separate object implementing
    the project properties dialog as a composite template widget.

 gladeui/Makefile.am                 |   14 +-
 gladeui/glade-project-properties.c  |  697 ++++
 gladeui/glade-project-properties.h  |   62 +
 gladeui/glade-project-properties.ui |   15 +-
 gladeui/glade-project.c             | 6170 ++++++++++++++++-------------------
 gladeui/glade-project.h             |    6 +
 po/POTFILES.in                      |    1 +
 7 files changed, 3647 insertions(+), 3318 deletions(-)
---
diff --git a/gladeui/Makefile.am b/gladeui/Makefile.am
index 3be90a9..c7b31f5 100644
--- a/gladeui/Makefile.am
+++ b/gladeui/Makefile.am
@@ -107,6 +107,7 @@ libgladeui_2_la_SOURCES = \
        glade-popup.c \
        glade-preview.c \
        glade-project.c \
+       glade-project-properties.c \
        glade-property.c \
        glade-property-class.c \
        glade-property-label.c \
@@ -176,16 +177,17 @@ libgladeuiinclude_HEADERS = \
        glade-xml-utils.h
 
 noinst_HEADERS = \
-       gladeui-resources.h \
-       glade-marshallers.h \
+       glade-accumulators.h \
        glade-design-layout.h \
+       glade-design-private.h \
+       glade-marshallers.h \
        glade-object-stub.h \
+       glade-path.h \
        glade-popup.h \
-       glade-accumulators.h \
-       glade-design-private.h \
-       glade-preview-tokens.h \
        glade-preview.h \
-       glade-path.h
+       glade-preview-tokens.h \
+       glade-project-properties.h \
+       gladeui-resources.h
 
 if PLATFORM_WIN32
 libgladeui_2_la_LDFLAGS += -no-undefined
diff --git a/gladeui/glade-project-properties.c b/gladeui/glade-project-properties.c
new file mode 100644
index 0000000..e3103bb
--- /dev/null
+++ b/gladeui/glade-project-properties.c
@@ -0,0 +1,697 @@
+/*
+ * Copyright (C) 2013 Tristan Van Berkom.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public 
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Authors:
+ *   Tristan Van Berkom <tvb gnome org>
+ */
+
+#include <config.h>
+#include <glib/gi18n-lib.h>
+
+#include "glade-project-properties.h"
+#include "glade-project.h"
+#include "glade-command.h"
+#include "glade-app.h"
+#include "glade-utils.h"
+
+/* GObjectClass */
+static void     glade_project_properties_finalize     (GObject                *object);
+static void     glade_project_properties_set_property (GObject                *object,
+                                                      guint                   prop_id,
+                                                      const GValue           *value,
+                                                      GParamSpec             *pspec);
+
+/* UI Callbacks */
+static void     on_template_combo_box_changed         (GtkComboBox            *combo,
+                                                      GladeProjectProperties *properties);
+static void     on_template_checkbutton_toggled       (GtkToggleButton        *togglebutton,
+                                                      GladeProjectProperties *properties);
+static void     resource_default_toggled              (GtkWidget              *widget,
+                                                      GladeProjectProperties *properties);
+static void     resource_relative_toggled             (GtkWidget              *widget,
+                                                      GladeProjectProperties *properties);
+static void     resource_fullpath_toggled             (GtkWidget              *widget,
+                                                      GladeProjectProperties *properties);
+static void     resource_path_activated               (GtkEntry               *entry,
+                                                      GladeProjectProperties *properties);
+static void     resource_full_path_set                (GtkFileChooserButton   *button,
+                                                      GladeProjectProperties *properties);
+static void     verify_clicked                        (GtkWidget              *button,
+                                                      GladeProjectProperties *properties);
+static void     on_domain_entry_changed               (GtkWidget              *entry,
+                                                      GladeProjectProperties *properties);
+static void     target_button_clicked                 (GtkWidget              *widget,
+                                                      GladeProjectProperties *properties);
+
+/* Project callbacks */
+static void     project_resource_path_changed         (GladeProject           *project,
+                                                      GParamSpec             *pspec,
+                                                      GladeProjectProperties *properties);
+static void     project_template_changed              (GladeProject           *project,
+                                                      GParamSpec             *pspec,
+                                                      GladeProjectProperties *properties);
+static void     project_domain_changed                (GladeProject           *project,
+                                                      GParamSpec             *pspec,
+                                                      GladeProjectProperties *properties);
+static void     project_targets_changed               (GladeProject           *project,
+                                                      GladeProjectProperties *properties);
+
+struct _GladeProjectPropertiesPrivate
+{
+  GladeProject *project;
+
+  GtkWidget *project_wide_radio;
+  GtkWidget *toplevel_contextual_radio;
+  GtkWidget *toolkit_box;
+
+  GtkWidget *resource_default_radio;
+  GtkWidget *resource_relative_radio;
+  GtkWidget *resource_fullpath_radio;
+  GtkWidget *relative_path_entry;
+  GtkWidget *full_path_button;
+  GtkWidget *domain_entry;
+  GtkWidget *template_combobox;
+  GtkWidget *template_checkbutton;
+
+  GHashTable *target_radios;
+};
+
+enum
+{
+  PROP_0,
+  PROP_PROJECT,
+};
+
+G_DEFINE_TYPE (GladeProjectProperties, glade_project_properties, GTK_TYPE_DIALOG);
+
+/********************************************************
+ *                  Class/Instance Init                 *
+ ********************************************************/
+static void
+glade_project_properties_init (GladeProjectProperties *properties)
+{
+  GladeProjectPropertiesPrivate *priv;
+
+  properties->priv = priv =
+    G_TYPE_INSTANCE_GET_PRIVATE (properties,
+                                GLADE_TYPE_PROJECT_PROPERTIES,
+                                GladeProjectPropertiesPrivate);
+
+  priv->target_radios = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                               g_free, NULL);
+
+  gtk_widget_init_template (GTK_WIDGET (properties));
+}
+
+static void
+glade_project_properties_class_init (GladeProjectPropertiesClass *klass)
+{
+  GObjectClass *gobject_class;
+  GtkWidgetClass *widget_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  widget_class  = GTK_WIDGET_CLASS (klass);
+
+  gobject_class->finalize = glade_project_properties_finalize;
+  gobject_class->set_property = glade_project_properties_set_property;
+
+  g_object_class_install_property
+    (gobject_class, PROP_PROJECT,
+     g_param_spec_object ("project", _("Project"),
+                         _("The project this properties dialog was created for"),
+                         GLADE_TYPE_PROJECT,
+                         G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+
+  /* Setup the template GtkBuilder xml for this class
+   */
+  gtk_widget_class_set_template_from_resource (widget_class, 
"/org/gnome/gladeui/glade-project-properties.ui");
+
+  /* Define the relationship of the private entry and the entry defined in the xml
+   */
+  gtk_widget_class_bind_child (widget_class, GladeProjectPropertiesPrivate, resource_default_radio);
+  gtk_widget_class_bind_child (widget_class, GladeProjectPropertiesPrivate, resource_relative_radio);
+  gtk_widget_class_bind_child (widget_class, GladeProjectPropertiesPrivate, resource_fullpath_radio);
+  gtk_widget_class_bind_child (widget_class, GladeProjectPropertiesPrivate, relative_path_entry);
+  gtk_widget_class_bind_child (widget_class, GladeProjectPropertiesPrivate, full_path_button);
+  gtk_widget_class_bind_child (widget_class, GladeProjectPropertiesPrivate, domain_entry);
+  gtk_widget_class_bind_child (widget_class, GladeProjectPropertiesPrivate, template_checkbutton);
+  gtk_widget_class_bind_child (widget_class, GladeProjectPropertiesPrivate, template_combobox);
+  gtk_widget_class_bind_child (widget_class, GladeProjectPropertiesPrivate, toolkit_box);
+
+  /* Declare the callback ports that this widget class exposes, to bind with <signal>
+   * connections defined in the GtkBuilder xml
+   */
+  gtk_widget_class_bind_callback (widget_class, on_template_combo_box_changed);
+  gtk_widget_class_bind_callback (widget_class, on_template_checkbutton_toggled);
+  gtk_widget_class_bind_callback (widget_class, resource_default_toggled);
+  gtk_widget_class_bind_callback (widget_class, resource_relative_toggled);
+  gtk_widget_class_bind_callback (widget_class, resource_fullpath_toggled);
+  gtk_widget_class_bind_callback (widget_class, resource_path_activated);
+  gtk_widget_class_bind_callback (widget_class, resource_full_path_set);
+  gtk_widget_class_bind_callback (widget_class, verify_clicked);
+  gtk_widget_class_bind_callback (widget_class, on_domain_entry_changed);
+
+  g_type_class_add_private (gobject_class, sizeof (GladeProjectPropertiesPrivate));
+}
+
+/********************************************************
+ *                     GObjectClass                     *
+ ********************************************************/
+static void
+glade_project_properties_finalize (GObject *object)
+{
+  GladeProjectProperties        *properties = GLADE_PROJECT_PROPERTIES (object);
+  GladeProjectPropertiesPrivate *priv = properties->priv;
+
+  g_hash_table_destroy (priv->target_radios);
+
+  G_OBJECT_CLASS (glade_project_properties_parent_class)->finalize (object);
+}
+
+static void
+target_version_box_fill (GladeProjectProperties *properties)
+{
+  GladeProjectPropertiesPrivate *priv = properties->priv;
+  GladeProject *project = priv->project;
+  GtkWidget *vbox = priv->toolkit_box;
+  GtkWidget *label, *active_radio, *target_radio, *hbox;
+  GList *list, *targets;
+
+  /* Add stuff to vbox */
+  for (list = glade_app_get_catalogs (); list; list = g_list_next (list))
+    {
+      GladeCatalog *catalog = list->data;
+      gint minor, major;
+
+      /* Skip if theres only one option */
+      if (g_list_length (glade_catalog_get_targets (catalog)) <= 1)
+        continue;
+
+      glade_project_get_target_version (project,
+                                        glade_catalog_get_name (catalog),
+                                        &major, &minor);
+
+      /* Special case to mark GTK+ in upper case */
+      if (strcmp (glade_catalog_get_name (catalog), "gtk+") == 0)
+        label = gtk_label_new ("GTK+");
+      else
+        label = gtk_label_new (glade_catalog_get_name (catalog));
+      gtk_misc_set_alignment (GTK_MISC (label), 0.0F, 0.5F);
+
+      gtk_widget_show (label);
+      gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 2);
+      hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+
+      active_radio = target_radio = NULL;
+
+      for (targets = glade_catalog_get_targets (catalog);
+           targets; targets = targets->next)
+        {
+          GladeTargetableVersion *version = targets->data;
+          gchar *name = g_strdup_printf ("%d.%d",
+                                         version->major,
+                                         version->minor);
+
+          if (!target_radio)
+            target_radio = gtk_radio_button_new_with_label (NULL, name);
+          else
+            target_radio =
+                gtk_radio_button_new_with_label_from_widget
+                (GTK_RADIO_BUTTON (target_radio), name);
+          g_free (name);
+
+          g_signal_connect (G_OBJECT (target_radio), "clicked",
+                            G_CALLBACK (target_button_clicked), properties);
+
+          g_object_set_data (G_OBJECT (target_radio), "version", version);
+          g_object_set_data (G_OBJECT (target_radio), "catalog",
+                             (gchar *) glade_catalog_get_name (catalog));
+
+          gtk_widget_show (target_radio);
+          gtk_box_pack_end (GTK_BOX (hbox), target_radio, TRUE, TRUE, 2);
+
+          if (major == version->major && minor == version->minor)
+            active_radio = target_radio;
+
+        }
+
+      if (active_radio)
+        {
+          gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (active_radio), TRUE);
+          g_hash_table_insert (priv->target_radios,
+                               g_strdup (glade_catalog_get_name (catalog)),
+                               gtk_radio_button_get_group (GTK_RADIO_BUTTON
+                                                           (active_radio)));
+        }
+      else
+        g_warning ("Corrupt catalog versions");
+
+      gtk_widget_show (hbox);
+      gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 2);
+    }
+}
+
+static void
+update_prefs_for_resource_path (GladeProjectProperties *properties)
+{
+  GladeProjectPropertiesPrivate *priv = properties->priv;
+  
+  gtk_widget_set_sensitive (priv->full_path_button, FALSE);
+  gtk_widget_set_sensitive (priv->relative_path_entry, FALSE);
+
+  g_signal_handlers_block_by_func (priv->resource_default_radio,
+                                   G_CALLBACK (resource_default_toggled),
+                                   properties);
+  g_signal_handlers_block_by_func (priv->resource_relative_radio,
+                                   G_CALLBACK (resource_relative_toggled),
+                                   properties);
+  g_signal_handlers_block_by_func (priv->resource_fullpath_radio,
+                                   G_CALLBACK (resource_fullpath_toggled),
+                                   properties);
+  g_signal_handlers_block_by_func (priv->relative_path_entry,
+                                   G_CALLBACK (resource_path_activated),
+                                   properties);
+
+  if (glade_project_get_resource_path (priv->project) == NULL)
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->resource_default_radio), TRUE);
+  else if (glade_project_get_resource_path (priv->project))
+    {
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->resource_fullpath_radio), TRUE);
+      gtk_widget_set_sensitive (priv->full_path_button, TRUE);
+    }
+  else
+    {
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->resource_relative_radio), TRUE);
+      gtk_widget_set_sensitive (priv->relative_path_entry, TRUE);
+    }
+
+  gtk_entry_set_text (GTK_ENTRY (priv->relative_path_entry),
+                     glade_project_get_resource_path (priv->project) ? 
+                     glade_project_get_resource_path (priv->project) : "");
+
+  g_signal_handlers_unblock_by_func (priv->resource_default_radio,
+                                     G_CALLBACK (resource_default_toggled),
+                                     properties);
+  g_signal_handlers_unblock_by_func (priv->resource_relative_radio,
+                                     G_CALLBACK (resource_relative_toggled),
+                                     properties);
+  g_signal_handlers_unblock_by_func (priv->resource_fullpath_radio,
+                                     G_CALLBACK (resource_fullpath_toggled),
+                                     properties);
+  g_signal_handlers_unblock_by_func (priv->relative_path_entry,
+                                     G_CALLBACK (resource_path_activated),
+                                     properties);
+}
+
+static void
+glade_project_properties_set_project (GladeProjectProperties *properties,
+                                     GladeProject           *project)
+{
+  GladeProjectPropertiesPrivate *priv = properties->priv;
+
+  /* No strong reference, we belong to the project */
+  g_assert (priv->project == NULL);
+  priv->project = project;
+
+  g_signal_connect (priv->project, "notify::resource-path",
+                   G_CALLBACK (project_resource_path_changed), properties);
+  g_signal_connect (priv->project, "notify::template",
+                   G_CALLBACK (project_template_changed), properties);
+  g_signal_connect (priv->project, "notify::translation-domain",
+                   G_CALLBACK (project_domain_changed), properties);
+  g_signal_connect (priv->project, "targets-changed",
+                   G_CALLBACK (project_targets_changed), properties);
+
+  target_version_box_fill (properties);
+  update_prefs_for_resource_path (properties);
+
+  project_template_changed (project, NULL, properties);
+  project_domain_changed (project, NULL, properties);
+}
+
+static void
+glade_project_properties_set_property (GObject *object,
+                                      guint prop_id,
+                                      const GValue *value,
+                                      GParamSpec *pspec)
+{
+  switch (prop_id)
+    {
+    case PROP_PROJECT:
+      glade_project_properties_set_project (GLADE_PROJECT_PROPERTIES (object),
+                                           g_value_get_object (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+/********************************************************
+ *                     Callbacks                        *
+ ********************************************************/
+static void
+target_button_clicked (GtkWidget              *widget,
+                      GladeProjectProperties *properties)
+{
+  GladeProjectPropertiesPrivate *priv = properties->priv;
+  GladeTargetableVersion        *version = g_object_get_data (G_OBJECT (widget), "version");
+  gchar                         *catalog = g_object_get_data (G_OBJECT (widget), "catalog");
+
+  glade_command_set_project_target (priv->project, catalog, version->major, version->minor);
+}
+
+static void
+resource_default_toggled (GtkWidget              *widget,
+                         GladeProjectProperties *properties)
+{
+  GladeProjectPropertiesPrivate *priv = properties->priv;
+
+  if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
+    return;
+
+  glade_project_set_resource_path (priv->project, NULL);
+  gtk_widget_set_sensitive (priv->relative_path_entry, FALSE);
+  gtk_widget_set_sensitive (priv->full_path_button, FALSE);
+}
+
+static void
+resource_relative_toggled (GtkWidget              *widget,
+                          GladeProjectProperties *properties)
+{
+  GladeProjectPropertiesPrivate *priv = properties->priv;
+
+  if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
+    return;
+
+  gtk_widget_set_sensitive (priv->relative_path_entry, TRUE);
+  gtk_widget_set_sensitive (priv->full_path_button, FALSE);
+}
+
+static void
+resource_fullpath_toggled (GtkWidget              *widget,
+                          GladeProjectProperties *properties)
+{
+  GladeProjectPropertiesPrivate *priv = properties->priv;
+
+  if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
+    return;
+
+  gtk_widget_set_sensitive (priv->relative_path_entry, FALSE);
+  gtk_widget_set_sensitive (priv->full_path_button, TRUE);
+}
+
+static void
+resource_path_activated (GtkEntry *entry, GladeProjectProperties *properties)
+{
+  GladeProjectPropertiesPrivate *priv = properties->priv;
+  const gchar *text = gtk_entry_get_text (entry);
+
+  glade_project_set_resource_path (priv->project, text);
+}
+
+static void
+resource_full_path_set (GtkFileChooserButton *button, GladeProjectProperties *properties)
+{
+  GladeProjectPropertiesPrivate *priv = properties->priv;
+  gchar *text = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (button));
+
+  glade_project_set_resource_path (priv->project, text);
+  g_free (text);
+}
+
+static void
+on_template_combo_box_changed (GtkComboBox            *combo,
+                              GladeProjectProperties *properties)
+{
+  GladeProjectPropertiesPrivate *priv = properties->priv;
+  GtkTreeIter iter;
+
+  if (gtk_combo_box_get_active_iter (combo, &iter))
+    {
+      GladeWidget *gwidget;
+      GObject *object;
+
+      gtk_tree_model_get (gtk_combo_box_get_model (combo), &iter,
+                          GLADE_PROJECT_MODEL_COLUMN_OBJECT, &object, -1);
+      
+      gwidget = glade_widget_get_from_gobject (object);
+
+      glade_command_set_project_template (priv->project, gwidget);
+    }
+}
+
+static void
+on_template_checkbutton_toggled (GtkToggleButton        *togglebutton,
+                                 GladeProjectProperties *properties)
+{
+  GladeProjectPropertiesPrivate *priv = properties->priv;
+  gboolean active = gtk_toggle_button_get_active (togglebutton);
+  gboolean composite = FALSE;
+  
+  if (active)
+    {
+      GList *l;
+
+      for (l = glade_project_toplevels (priv->project); l; l = l->next)
+       {
+         GObject *object = l->data;
+         GladeWidget *gwidget;
+
+         gwidget = glade_widget_get_from_gobject (object);
+
+         if (GTK_IS_WIDGET (object))
+           {
+             glade_command_set_project_template (priv->project, gwidget);
+             composite = TRUE;
+             break;
+           }
+       }
+
+      if (!composite)
+       gtk_toggle_button_set_active (togglebutton, FALSE);
+    }
+  else
+    glade_command_set_project_template (priv->project, NULL);
+}
+
+static gboolean
+template_visible_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
+{
+  GtkTreeIter parent;
+  gboolean visible;
+  GObject *object;
+
+  visible = !gtk_tree_model_iter_parent (model, &parent, iter);
+
+  if (visible)
+    {
+      gtk_tree_model_get (model, iter,
+                         GLADE_PROJECT_MODEL_COLUMN_OBJECT, &object,
+                         -1);
+
+      visible = GTK_IS_WIDGET (object);
+      g_object_unref (object);
+    }
+
+  return visible;
+}
+
+static GtkTreeModel *
+glade_project_toplevel_model_filter_new (GladeProjectProperties *properties)
+{
+  GladeProjectPropertiesPrivate *priv = properties->priv;
+  GtkTreeModel *model;
+
+  model = gtk_tree_model_filter_new (GTK_TREE_MODEL (priv->project), NULL);
+  gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (model),
+                                          template_visible_func, NULL, NULL);
+  return model;
+}
+
+static void
+verify_clicked (GtkWidget *button, GladeProjectProperties *properties)
+{
+  GladeProjectPropertiesPrivate *priv = properties->priv;
+
+  if (glade_project_verify (priv->project, FALSE,
+                           GLADE_VERIFY_VERSIONS     |
+                           GLADE_VERIFY_DEPRECATIONS |
+                           GLADE_VERIFY_UNRECOGNIZED))
+    {
+      gchar *name = glade_project_get_name (priv->project);
+      glade_util_ui_message (glade_app_get_window (),
+                             GLADE_UI_INFO, NULL,
+                             _("Project %s has no deprecated widgets "
+                               "or version mismatches."), name);
+      g_free (name);
+    }
+}
+
+static void
+on_domain_entry_changed (GtkWidget *entry, GladeProjectProperties *properties)
+{
+  GladeProjectPropertiesPrivate *priv = properties->priv;
+
+  glade_command_set_project_domain (priv->project, gtk_entry_get_text (GTK_ENTRY (entry)));
+}
+
+/******************************************************
+ *                   Project Callbacks                *
+ ******************************************************/
+static void
+project_targets_changed (GladeProject           *project,
+                        GladeProjectProperties *properties)
+{
+  GladeProjectPropertiesPrivate *priv = properties->priv;
+  GList *list;
+  GSList *radios, *l;
+
+  /* For each catalog */
+  for (list = glade_app_get_catalogs (); list; list = g_list_next (list))
+    {
+      GladeTargetableVersion *version;
+      GladeCatalog *catalog = list->data;
+      gint minor, major;
+
+      /* Skip if theres only one option */
+      if (g_list_length (glade_catalog_get_targets (catalog)) <= 1)
+        continue;
+
+      /* Fetch the version for this project */
+      glade_project_get_target_version (priv->project,
+                                        glade_catalog_get_name (catalog),
+                                        &major, &minor);
+
+      /* Fetch the radios for this catalog  */
+      if (priv->target_radios &&
+         (radios = g_hash_table_lookup (priv->target_radios, glade_catalog_get_name (catalog))) != NULL)
+       {
+         for (l = radios; l; l = l->next)
+           g_signal_handlers_block_by_func (G_OBJECT (l->data),
+                                            G_CALLBACK (target_button_clicked),
+                                            properties);
+
+         for (l = radios; l; l = l->next)
+           {
+             GtkWidget *radio = l->data;
+
+             /* Activate the appropriate button for the project/catalog */
+             version = g_object_get_data (G_OBJECT (radio), "version");
+             if (version->major == major && version->minor == minor)
+               {
+                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio), TRUE);
+                 break;
+               }
+           }
+
+         for (l = radios; l; l = l->next)
+           g_signal_handlers_unblock_by_func (G_OBJECT (l->data),
+                                              G_CALLBACK (target_button_clicked),
+                                              properties);
+       }
+    }
+}
+
+static void
+project_domain_changed (GladeProject           *project,
+                       GParamSpec             *pspec,
+                       GladeProjectProperties *properties)
+{
+  GladeProjectPropertiesPrivate *priv = properties->priv;
+  const gchar *domain;
+
+  domain = glade_project_get_translation_domain (priv->project);
+
+  g_signal_handlers_block_by_func (priv->domain_entry, on_domain_entry_changed, properties);
+  gtk_entry_set_text (GTK_ENTRY (priv->domain_entry), domain ? domain : "");
+  g_signal_handlers_unblock_by_func (priv->domain_entry, on_domain_entry_changed, properties);
+}
+
+static void
+project_resource_path_changed (GladeProject           *project,
+                              GParamSpec             *pspec,
+                              GladeProjectProperties *properties)
+{
+  update_prefs_for_resource_path (properties);
+}
+
+static void
+project_template_changed (GladeProject           *project,
+                         GParamSpec             *pspec,
+                         GladeProjectProperties *properties)
+{
+  GladeProjectPropertiesPrivate *priv = properties->priv;
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+  gboolean valid;
+  gboolean template_found = FALSE;
+
+  g_signal_handlers_block_by_func (priv->template_combobox, on_template_combo_box_changed, properties);
+  g_signal_handlers_block_by_func (priv->template_checkbutton, on_template_checkbutton_toggled, properties);
+
+  model = gtk_combo_box_get_model (GTK_COMBO_BOX (priv->template_combobox));
+  if (!model)
+    {
+      model = glade_project_toplevel_model_filter_new (properties);
+
+      gtk_combo_box_set_model (GTK_COMBO_BOX (priv->template_combobox), model);
+      g_object_unref (model);
+    }
+
+  valid = gtk_tree_model_get_iter_first (model, &iter);
+  while (valid)
+    {
+      GladeWidget *gwidget;
+      GObject *obj;
+      
+      gtk_tree_model_get (model, &iter,
+                          GLADE_PROJECT_MODEL_COLUMN_OBJECT, &obj,
+                          -1);
+
+      gwidget = glade_widget_get_from_gobject (obj);
+      g_object_unref (obj);
+
+      if (gwidget == glade_project_get_template (priv->project))
+       {
+          gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->template_combobox), &iter);
+
+         template_found = TRUE;
+         break;
+        }
+
+      valid = gtk_tree_model_iter_next (model, &iter);
+    }
+
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->template_checkbutton), template_found);
+  gtk_widget_set_sensitive (priv->template_combobox, template_found);
+
+  if (!template_found && gtk_combo_box_get_model (GTK_COMBO_BOX (priv->template_combobox)))
+    gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->template_combobox), NULL);
+
+  g_signal_handlers_unblock_by_func (priv->template_combobox, on_template_combo_box_changed, properties);
+  g_signal_handlers_unblock_by_func (priv->template_checkbutton, on_template_checkbutton_toggled, 
properties);
+}
+
+/******************************************************
+ *                         API                        *
+ ******************************************************/
+GtkWidget *
+glade_project_properties_new (GladeProject *project)
+{
+  return g_object_new (GLADE_TYPE_PROJECT_PROPERTIES, "project", project, NULL);
+}
diff --git a/gladeui/glade-project-properties.h b/gladeui/glade-project-properties.h
new file mode 100644
index 0000000..e9684f8
--- /dev/null
+++ b/gladeui/glade-project-properties.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2013 Tristan Van Berkom.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public 
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Authors:
+ *   Tristan Van Berkom <tvb gnome org>
+ */
+
+#ifndef __GLADE_PROJECT_PROPERTIES_H__
+#define __GLADE_PROJECT_PROPERTIES_H__
+
+#include <gtk/gtk.h>
+#include <gladeui/glade-xml-utils.h>
+
+G_BEGIN_DECLS
+
+#define GLADE_TYPE_PROJECT_PROPERTIES             (glade_project_properties_get_type ())
+#define GLADE_PROJECT_PROPERTIES(obj)             (G_TYPE_CHECK_INSTANCE_CAST \
+                                                  ((obj), GLADE_TYPE_PROJECT_PROPERTIES, 
GladeProjectProperties))
+#define GLADE_PROJECT_PROPERTIES_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST \
+                                                  ((klass), GLADE_TYPE_PROJECT_PROPERTIES, 
GladeProjectPropertiesClass))
+#define GLADE_IS_PROJECT_PROPERTIES(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
GLADE_TYPE_PROJECT_PROPERTIES))
+#define GLADE_IS_PROJECT_PROPERTIES_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), 
GLADE_TYPE_PROJECT_PROPERTIES))
+#define GLADE_PROJECT_PROPERTIES_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS \
+                                                  ((obj), GLADE_TYPE_PROJECT_PROPERTIES, 
GladeProjectPropertiesClass))
+
+typedef struct _GladeProjectProperties             GladeProjectProperties;
+typedef struct _GladeProjectPropertiesClass        GladeProjectPropertiesClass;
+typedef struct _GladeProjectPropertiesPrivate      GladeProjectPropertiesPrivate;
+
+struct _GladeProjectProperties
+{
+  /*< private >*/
+  GtkDialog dialog;
+
+  GladeProjectPropertiesPrivate *priv;
+};
+
+struct _GladeProjectPropertiesClass
+{
+  GtkDialogClass parent_class;
+};
+
+GType             glade_project_properties_get_type         (void) G_GNUC_CONST;
+GtkWidget        *glade_project_properties_new              (GladeProject *project);
+
+G_END_DECLS
+
+#endif /* __GLADE_PROJECT_PROPERTIES_H__ */
diff --git a/gladeui/glade-project-properties.ui b/gladeui/glade-project-properties.ui
index e3def56..6af6713 100644
--- a/gladeui/glade-project-properties.ui
+++ b/gladeui/glade-project-properties.ui
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface domain="glade">
-  <!-- interface-requires gtk+ 3.6 -->
-  <object class="GtkDialog" id="prefs_dialog">
+  <!-- interface-requires gtk+ 3.8 -->
+  <template class="GladeProjectProperties" parent="GtkDialog">
     <property name="can_focus">False</property>
     <property name="border_width">5</property>
     <property name="resizable">False</property>
@@ -54,6 +54,7 @@
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
                         <property name="invisible_char">●</property>
+                        <signal name="changed" handler="on_domain_entry_changed" swapped="no"/>
                       </object>
                       <packing>
                         <property name="left_attach">1</property>
@@ -67,6 +68,7 @@
                         <property name="visible">True</property>
                         <property name="sensitive">False</property>
                         <property name="can_focus">False</property>
+                        <signal name="changed" handler="on_template_combo_box_changed" swapped="no"/>
                         <child>
                           <object class="GtkCellRendererPixbuf" id="cellrenderertext1"/>
                           <attributes>
@@ -95,6 +97,7 @@
                         <property name="receives_default">False</property>
                         <property name="xalign">0</property>
                         <property name="draw_indicator">True</property>
+                        <signal name="toggled" handler="on_template_checkbutton_toggled" swapped="no"/>
                       </object>
                       <packing>
                         <property name="left_attach">0</property>
@@ -146,6 +149,7 @@
                         <property name="xalign">0</property>
                         <property name="active">True</property>
                         <property name="draw_indicator">True</property>
+                        <signal name="toggled" handler="resource_default_toggled" swapped="no"/>
                       </object>
                       <packing>
                         <property name="left_attach">0</property>
@@ -164,6 +168,7 @@
                         <property name="active">True</property>
                         <property name="draw_indicator">True</property>
                         <property name="group">resource_default_radio</property>
+                        <signal name="toggled" handler="resource_relative_toggled" swapped="no"/>
                       </object>
                       <packing>
                         <property name="left_attach">0</property>
@@ -182,6 +187,7 @@
                         <property name="active">True</property>
                         <property name="draw_indicator">True</property>
                         <property name="group">resource_default_radio</property>
+                        <signal name="toggled" handler="resource_fullpath_toggled" swapped="no"/>
                       </object>
                       <packing>
                         <property name="left_attach">0</property>
@@ -198,6 +204,7 @@
                         <property name="orientation">vertical</property>
                         <property name="action">select-folder</property>
                         <property name="title" translatable="yes">Choose a path to load image 
resources</property>
+                        <signal name="file-set" handler="resource_full_path_set" swapped="no"/>
                       </object>
                       <packing>
                         <property name="left_attach">1</property>
@@ -212,6 +219,7 @@
                         <property name="can_focus">True</property>
                         <property name="hexpand">True</property>
                         <property name="invisible_char">●</property>
+                        <signal name="activate" handler="resource_path_activated" swapped="no"/>
                       </object>
                       <packing>
                         <property name="left_attach">1</property>
@@ -294,6 +302,7 @@
                 <property name="tooltip_text" translatable="yes">Verify that the project does not use any  
properties,
 signals or widgets which are not available in the target version</property>
                 <property name="use_underline">True</property>
+                <signal name="clicked" handler="verify_clicked" swapped="no"/>
               </object>
               <packing>
                 <property name="expand">False</property>
@@ -329,5 +338,5 @@ signals or widgets which are not available in the target version</property>
     <action-widgets>
       <action-widget response="-3">close_button</action-widget>
     </action-widgets>
-  </object>
+  </template>
 </interface>
diff --git a/gladeui/glade-project.c b/gladeui/glade-project.c
index 3f310f4..1bc014e 100644
--- a/gladeui/glade-project.c
+++ b/gladeui/glade-project.c
@@ -52,40 +52,34 @@
 #include "glade-command.h"
 #include "glade-name-context.h"
 #include "glade-object-stub.h"
-
-#define VALID_ITER(project, iter) ((iter)!= NULL && G_IS_OBJECT ((iter)->user_data) && 
((GladeProject*)(project))->priv->stamp == (iter)->stamp)
-
-enum
-{
-  ADD_WIDGET,
-  REMOVE_WIDGET,
-  WIDGET_NAME_CHANGED,
-  SELECTION_CHANGED,
-  CLOSE,
-  CHANGED,
-  PARSE_BEGAN,
-  PARSE_FINISHED,
-  TARGETS_CHANGED,
-  LOAD_PROGRESS,
-  WIDGET_VISIBILITY_CHANGED,
-  LAST_SIGNAL
-};
-
-enum
-{
-  PROP_0,
-  PROP_MODIFIED,
-  PROP_HAS_SELECTION,
-  PROP_PATH,
-  PROP_READ_ONLY,
-  PROP_ADD_ITEM,
-  PROP_POINTER_MODE,
-  PROP_TRANSLATION_DOMAIN,
-  PROP_TEMPLATE,
-  N_PROPERTIES
-};
-
-static GParamSpec *properties[N_PROPERTIES];
+#include "glade-project-properties.h"
+
+static void     glade_project_target_version_for_adaptor
+                                                    (GladeProject       *project,
+                                                    GladeWidgetAdaptor *adaptor,
+                                                    gint               *major,
+                                                    gint               *minor);
+static void     glade_project_verify_properties     (GladeWidget        *widget);
+static void     glade_project_verify_project_for_ui (GladeProject       *project);
+static void     glade_project_verify_adaptor        (GladeProject       *project,
+                                                    GladeWidgetAdaptor *adaptor,
+                                                    const gchar        *path_name,
+                                                    GString            *string,
+                                                    GladeVerifyFlags    flags,
+                                                    gboolean            forwidget,
+                                                    GladeSupportMask   *mask);
+static void     glade_project_set_readonly          (GladeProject       *project,
+                                                    gboolean            readonly);
+static void     glade_project_set_modified          (GladeProject       *project,
+                                                    gboolean            modified);
+
+static void     glade_project_model_iface_init      (GtkTreeModelIface  *iface);
+static void     glade_project_model_get_iter_for_object
+                                                    (GladeProject       *project,
+                                                     GObject            *object,
+                                                     GtkTreeIter        *iter);
+static gint     glade_project_count_children        (GladeProject       *project, 
+                                                    GladeWidget        *parent);
 
 struct _GladeProjectPrivate
 {
@@ -138,20 +132,7 @@ struct _GladeProjectPrivate
 
   GList *unknown_catalogs; /* List of CatalogInfo catalogs */
 
-  /* Control on the properties dialog to update buttons etc when properties change */
   GtkWidget *prefs_dialog;
-  GtkWidget *project_wide_radio;
-  GtkWidget *toplevel_contextual_radio;
-  GHashTable *target_radios;
-
-  GtkWidget *resource_default_radio;
-  GtkWidget *resource_relative_radio;
-  GtkWidget *resource_fullpath_radio;
-  GtkWidget *relative_path_entry;
-  GtkWidget *full_path_button;
-  GtkWidget *domain_entry;
-  GtkWidget *template_combobox;
-  GtkWidget *template_checkbutton;
 
   /* Store previews, so we can kill them on close */
   GHashTable *previews;
@@ -180,53 +161,52 @@ typedef struct
   gint position;
 } CatalogInfo;
 
-static void glade_project_target_version_for_adaptor (GladeProject *project,
-                                                      GladeWidgetAdaptor *adaptor,
-                                                      gint *major,
-                                                      gint *minor);
-
-static void glade_project_set_readonly (GladeProject *project,
-                                        gboolean readonly);
-
-
-static gboolean glade_project_verify (GladeProject *project, gboolean saving, GladeVerifyFlags flags);
-static void     glade_project_verify_properties     (GladeWidget  *widget);
-static void     glade_project_verify_project_for_ui (GladeProject *project);
-
-static void glade_project_verify_adaptor (GladeProject *project,
-                                          GladeWidgetAdaptor *adaptor,
-                                          const gchar *path_name,
-                                          GString *string,
-                                          GladeVerifyFlags flags,
-                                          gboolean forwidget,
-                                          GladeSupportMask *mask);
-
-static GtkWidget *glade_project_build_prefs_dialog (GladeProject *project);
-
-static void target_button_clicked (GtkWidget *widget, GladeProject *project);
-static void update_prefs_for_resource_path (GladeProject *project);
-
-static void gtk_tree_model_iface_init (GtkTreeModelIface *iface);
-
-static void glade_project_model_get_iter_for_object (GladeProject *project,
-                                                     GObject *object,
-                                                     GtkTreeIter *iter);
-
-static gint glade_project_count_children (GladeProject *project, 
-                                          GladeWidget  *parent);
-
-static void glade_project_fix_template (GladeProject *project);
 
+enum
+{
+  ADD_WIDGET,
+  REMOVE_WIDGET,
+  WIDGET_NAME_CHANGED,
+  SELECTION_CHANGED,
+  CLOSE,
+  CHANGED,
+  PARSE_BEGAN,
+  PARSE_FINISHED,
+  TARGETS_CHANGED,
+  LOAD_PROGRESS,
+  WIDGET_VISIBILITY_CHANGED,
+  LAST_SIGNAL
+};
 
-static guint glade_project_signals[LAST_SIGNAL] = { 0 };
+enum
+{
+  PROP_0,
+  PROP_MODIFIED,
+  PROP_HAS_SELECTION,
+  PROP_PATH,
+  PROP_READ_ONLY,
+  PROP_ADD_ITEM,
+  PROP_POINTER_MODE,
+  PROP_TRANSLATION_DOMAIN,
+  PROP_TEMPLATE,
+  PROP_RESOURCE_PATH,
+  N_PROPERTIES
+};
 
+static GParamSpec       *glade_project_props[N_PROPERTIES];
+static guint             glade_project_signals[LAST_SIGNAL] = { 0 };
 static GladeIDAllocator *unsaved_number_allocator = NULL;
 
+
 #define GLADE_PROJECT_LARGE_PROJECT 40
 
+#define VALID_ITER(project, iter) \
+  ((iter)!= NULL && G_IS_OBJECT ((iter)->user_data) && \
+   ((GladeProject*)(project))->priv->stamp == (iter)->stamp)
+
 G_DEFINE_TYPE_WITH_CODE (GladeProject, glade_project, G_TYPE_OBJECT,
                          G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
-                                                gtk_tree_model_iface_init))
+                                                glade_project_model_iface_init))
 
 
 /*******************************************************************
@@ -352,7 +332,6 @@ glade_project_finalize (GObject *object)
 
   g_hash_table_destroy (project->priv->target_versions_major);
   g_hash_table_destroy (project->priv->target_versions_minor);
-  g_hash_table_destroy (project->priv->target_radios);
 
   glade_name_context_destroy (project->priv->widget_names);
 
@@ -393,6 +372,9 @@ glade_project_get_property (GObject *object,
     case PROP_TEMPLATE:
       g_value_set_object (value, project->priv->template);
       break;
+    case PROP_RESOURCE_PATH:
+      g_value_set_string (value, project->priv->resource_path);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -415,155 +397,16 @@ glade_project_set_property (GObject *object,
       glade_project_set_template (GLADE_PROJECT (object),
                                  g_value_get_object (value));
       break;
+    case PROP_RESOURCE_PATH:
+      glade_project_set_resource_path (GLADE_PROJECT (object),
+                                      g_value_get_string (value));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
     }
 }
 
-/**
- * glade_project_set_modified:
- * @project: a #GladeProject
- * @modified: Whether the project should be set as modified or not
- * @modification: The first #GladeCommand which caused the project to have unsaved changes
- *
- * Set's whether a #GladeProject should be flagged as modified or not. This is useful
- * for indicating that a project has unsaved changes. If @modified is #TRUE, then
- * @modification will be recorded as the first change which caused the project to 
- * have unsaved changes. @modified is #FALSE then @modification will be ignored.
- *
- * If @project is already flagged as modified, then calling this method with
- * @modified as #TRUE, will have no effect. Likewise, if @project is unmodified
- * then calling this method with @modified as #FALSE, will have no effect.
- *
- */
-static void
-glade_project_set_modified (GladeProject *project, gboolean modified)
-{
-  GladeProjectPrivate *priv;
-
-  g_return_if_fail (GLADE_IS_PROJECT (project));
-
-  priv = project->priv;
-
-  if (priv->modified != modified)
-    {
-      priv->modified = !priv->modified;
-
-      if (!priv->modified)
-        {
-          priv->first_modification = project->priv->prev_redo_item;
-          priv->first_modification_is_na = FALSE;
-        }
-
-      g_object_notify_by_pspec (G_OBJECT (project), properties[PROP_MODIFIED]);
-    }
-}
-
-/**
- * glade_project_get_modified:
- * @project: a #GladeProject
- *
- * Get's whether the project has been modified since it was last saved.
- *
- * Returns: %TRUE if the project has been modified since it was last saved
- */
-gboolean
-glade_project_get_modified (GladeProject *project)
-{
-  g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
-
-  return project->priv->modified;
-}
-
-void
-glade_project_set_pointer_mode (GladeProject *project, GladePointerMode mode)
-{
-  g_return_if_fail (GLADE_IS_PROJECT (project));
-
-  if (project->priv->pointer_mode != mode)
-    {
-      project->priv->pointer_mode = mode;
-
-      g_object_notify_by_pspec (G_OBJECT (project), properties[PROP_POINTER_MODE]);
-    }
-}
-
-GladePointerMode
-glade_project_get_pointer_mode (GladeProject *project)
-{
-  g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
-
-  return project->priv->pointer_mode;
-}
-
-void
-glade_project_set_template (GladeProject       *project,
-                           GladeWidget        *widget)
-{
-  g_return_if_fail (GLADE_IS_PROJECT (project));
-  g_return_if_fail (widget == NULL || GLADE_IS_WIDGET (widget));
-
-  if (widget)
-    {
-      GObject *object = glade_widget_get_object (widget);
-
-      g_return_if_fail (GTK_IS_WIDGET (object));
-      g_return_if_fail (glade_widget_get_parent (widget) == NULL);
-      g_return_if_fail (glade_widget_get_project (widget) == project);
-    }
-
-  /* Let's not add any strong reference here, we already own the widget */
-  if (project->priv->template != widget)
-    {
-      if (project->priv->template)
-       glade_widget_set_is_composite (project->priv->template, FALSE);
-
-      project->priv->template = widget;
-
-      if (project->priv->template)
-       glade_widget_set_is_composite (project->priv->template, TRUE);
-
-      glade_project_fix_template (project);
-
-      g_object_notify_by_pspec (G_OBJECT (project), properties[PROP_TEMPLATE]);
-    }
-}
-
-GladeWidget *
-glade_project_get_template (GladeProject       *project)
-{
-  g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
-
-  return project->priv->template;
-}
-
-
-void
-glade_project_set_add_item (GladeProject *project, GladeWidgetAdaptor *adaptor)
-{
-  GladeProjectPrivate *priv;
-
-  g_return_if_fail (GLADE_IS_PROJECT (project));
-
-  priv = project->priv;
-
-  if (priv->add_item != adaptor)
-    {
-      priv->add_item = adaptor;
-
-      g_object_notify_by_pspec (G_OBJECT (project), properties[PROP_ADD_ITEM]);
-    }
-}
-
-GladeWidgetAdaptor *
-glade_project_get_add_item (GladeProject *project)
-{
-  g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
-
-  return project->priv->add_item;
-}
-
 /*******************************************************************
                           GladeProjectClass
  *******************************************************************/
@@ -780,7 +623,6 @@ glade_project_changed_impl (GladeProject *project,
     }
 }
 
-
 /*******************************************************************
                           Class Initializers
  *******************************************************************/
@@ -841,10 +683,7 @@ glade_project_init (GladeProject *project)
                                         (catalog));
     }
 
-  priv->target_radios = g_hash_table_new_full (g_str_hash, g_str_equal,
-                                               g_free, NULL);
-  priv->prefs_dialog = glade_project_build_prefs_dialog (project);
-
+  priv->prefs_dialog = glade_project_properties_new (project);
 }
 
 static void
@@ -1038,42 +877,42 @@ glade_project_class_init (GladeProjectClass *klass)
                     _glade_marshal_VOID__OBJECT_BOOLEAN,
                     G_TYPE_NONE, 2, GLADE_TYPE_WIDGET, G_TYPE_BOOLEAN);
 
-  properties[PROP_MODIFIED] =
+  glade_project_props[PROP_MODIFIED] =
     g_param_spec_boolean ("modified",
                           "Modified",
                           _("Whether project has been modified since it was last saved"),
                           FALSE,
                           G_PARAM_READABLE);
 
-  properties[PROP_HAS_SELECTION] =
+  glade_project_props[PROP_HAS_SELECTION] =
     g_param_spec_boolean ("has-selection",
                           _("Has Selection"),
                           _("Whether project has a selection"),
                           FALSE,
                           G_PARAM_READABLE);
 
-  properties[PROP_PATH] =
+  glade_project_props[PROP_PATH] =
     g_param_spec_string ("path",
                          _("Path"),
                          _("The filesystem path of the project"),
                          NULL,
                          G_PARAM_READABLE);
 
-  properties[PROP_READ_ONLY] =
+  glade_project_props[PROP_READ_ONLY] =
     g_param_spec_boolean ("read-only",
                           _("Read Only"),
                           _("Whether project is read-only"),
                           FALSE,
                           G_PARAM_READABLE);
 
-  properties[PROP_ADD_ITEM] = 
+  glade_project_props[PROP_ADD_ITEM] = 
     g_param_spec_object ("add-item",
                          _("Add Item"),
                          _("The current item to add to the project"),
                          GLADE_TYPE_WIDGET_ADAPTOR,
                          G_PARAM_READABLE);
 
-  properties[PROP_POINTER_MODE] =
+  glade_project_props[PROP_POINTER_MODE] =
     g_param_spec_enum ("pointer-mode",
                        _("Pointer Mode"),
                        _("The currently effective GladePointerMode"),
@@ -1081,4007 +920,3720 @@ glade_project_class_init (GladeProjectClass *klass)
                        GLADE_POINTER_SELECT,
                        G_PARAM_READABLE);
 
-  properties[PROP_TRANSLATION_DOMAIN] =
+  glade_project_props[PROP_TRANSLATION_DOMAIN] =
     g_param_spec_string ("translation-domain",
                          _("Translation Domain"),
                          _("The project translation domain"),
                          NULL,
                          G_PARAM_READWRITE);
   
-  properties[PROP_TEMPLATE] = 
+  glade_project_props[PROP_TEMPLATE] = 
     g_param_spec_object ("template",
                          _("Template"),
                          _("The project's template widget, if any"),
                          GLADE_TYPE_WIDGET,
                          G_PARAM_READWRITE);
 
+  glade_project_props[PROP_RESOURCE_PATH] =
+    g_param_spec_string ("resource-path",
+                         _("Resource Path"),
+                         _("Path to load images and resources in Glade's runtime"),
+                         NULL,
+                         G_PARAM_READWRITE);
+
   /* Install all properties */
-  g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+  g_object_class_install_properties (object_class, N_PROPERTIES, glade_project_props);
 
   g_type_class_add_private (klass, sizeof (GladeProjectPrivate));
 }
 
-/*******************************************************************
-                    Loading project code here
- *******************************************************************/
-
-/**
- * glade_project_new:
- *
- * Creates a new #GladeProject.
- *
- * Returns: a new #GladeProject
- */
-GladeProject *
-glade_project_new (void)
+/******************************************************************
+ *                    GtkTreeModelIface                           *
+ ******************************************************************/
+static GObject *
+glade_project_nth_child (GladeProject *project,
+                         GladeWidget  *parent, 
+                         gint          nth)
 {
-  GladeProject *project = g_object_new (GLADE_TYPE_PROJECT, NULL);
-  return project;
-}
+  GList   *children, *list;
+  GObject *child = NULL;
+  gint     i;
 
-/* Called when finishing loading a glade file to resolve object type properties
- */
-static void
-glade_project_fix_object_props (GladeProject *project)
-{
-  GList *l, *ll, *objects;
-  GValue *value;
-  GladeWidget *gwidget;
-  GladeProperty *property;
-  gchar *txt;
+  children = glade_widget_get_children (parent);
 
-  objects = g_list_copy (project->priv->objects);
-  for (l = objects; l; l = l->next)
+  for (list = children, i = 0; list; list = list->next)
     {
-      gwidget = glade_widget_get_from_gobject (l->data);
-
-      for (ll = glade_widget_get_properties (gwidget); ll; ll = ll->next)
-        {
-          GladePropertyClass *klass;
+      child = list->data;
 
-          property = GLADE_PROPERTY (ll->data);
-          klass    = glade_property_get_class (property);
+      if (!glade_project_has_object (project, child))
+         continue;      
 
-          if (glade_property_class_is_object (klass) &&
-              (txt = g_object_get_data (G_OBJECT (property),
-                                        "glade-loaded-object")) != NULL)
-            {
-              /* Parse the object list and set the property to it
-               * (this magicly works for both objects & object lists)
-               */
-              value = glade_property_class_make_gvalue_from_string (klass, txt, project);
+      if (i == nth)
+        break;
 
-              glade_property_set_value (property, value);
+      child = NULL;
+      i++;
+    }
 
-              g_value_unset (value);
-              g_free (value);
+  g_list_free (children);
 
-              g_object_set_data (G_OBJECT (property),
-                                 "glade-loaded-object", NULL);
-            }
-        }
-    }
-  g_list_free (objects);
+  return child;
 }
 
-static gchar *
-glade_project_read_requires_from_comment (GladeXmlNode *comment,
-                                          guint16 *major, guint16 *minor)
+static gint
+glade_project_child_position (GladeProject *project,
+                              GladeWidget  *parent, 
+                              GObject      *child)
 {
-  gint maj, min;
-  gchar *value, buffer[256];
-  gchar *required_lib = NULL;
-
-  if (!glade_xml_node_is_comment (comment))
-    return NULL;
+  GList   *children, *list;
+  GObject *iter;
+  gint     i, position = -1;
 
-  value = glade_xml_get_content (comment);
+  children = glade_widget_get_children (parent);
 
-  if (value &&
-      !strncmp (" interface-requires", value, strlen (" interface-requires")))
+  for (list = children, i = 0; list; list = list->next)
     {
-      if (sscanf (value, " interface-requires %s %d.%d", buffer, &maj, &min) == 3)
+      iter = list->data;
+
+      if (!glade_project_has_object (project, iter))
+        continue;
+
+      if (iter == child)
         {
-          if (major)
-            *major = maj;
-          if (minor)
-            *minor = min;
-          required_lib = g_strdup (buffer);
+          position = i;
+          break;
         }
+      i++;
     }
-  g_free (value);
 
-  return required_lib;
-}
+  g_list_free (children);
 
+  return position;
+}
 
-static gboolean
-glade_project_read_requires (GladeProject *project,
-                             GladeXmlNode *root_node,
-                             const gchar *path, gboolean *has_gtk_dep)
+static gint
+glade_project_count_children (GladeProject *project, GladeWidget *parent)
 {
+  GList   *children, *list;
+  GObject *iter;
+  gint     i;
 
-  GString *string = g_string_new (NULL);
-  GladeXmlNode *node;
-  gchar *required_lib = NULL;
-  gboolean loadable = TRUE;
-  guint16 major, minor;
-  gint position = 0;
+  children = glade_widget_get_children (parent);
 
-  for (node = glade_xml_node_get_children_with_comments (root_node);
-       node; node = glade_xml_node_next_with_comments (node))
+  for (list = children, i = 0; list; list = list->next)
     {
-      /* Skip non "requires" tags */
-      if (!(glade_xml_node_verify_silent (node, GLADE_XML_TAG_REQUIRES) ||
-            (required_lib =
-             glade_project_read_requires_from_comment (node, &major, &minor))))
-        continue;
-
-      if (!required_lib)
-        {
-          required_lib =
-              glade_xml_get_property_string_required (node, GLADE_XML_TAG_LIB,
-                                                      NULL);
-          glade_xml_get_property_version (node, GLADE_XML_TAG_VERSION,
-                                          &major, &minor);
-        }
+      iter = list->data;
 
-      if (!required_lib)
+      if (!glade_project_has_object (project, iter))
         continue;
+      i++;
+    }
 
-      /* Dont mention gtk+ as a required lib in 
-       * the generated glade file
-       */
-      if (!glade_catalog_is_loaded (required_lib))
-        {
-          CatalogInfo *data = g_new0(CatalogInfo, 1);
-          
-          data->catalog = required_lib;
-          data->position = position;
-
-          /* Keep a list of unknown catalogs to avoid loosing the requirement */
-          project->priv->unknown_catalogs = g_list_append (project->priv->unknown_catalogs,
-                                                           data);
-          /* Also keep the version */
-          glade_project_set_target_version (project, required_lib, major, minor);
-
-          if (!loadable)
-            g_string_append (string, ", ");
-
-          g_string_append (string, required_lib);
-          loadable = FALSE;
-        }
-      else
-        {
-          if (has_gtk_dep && strcmp (required_lib, "gtk+") == 0)
-            *has_gtk_dep = TRUE;
+  g_list_free (children);
 
-          glade_project_set_target_version
-              (project, required_lib, major, minor);
-          g_free (required_lib);
-        }
+  return i;
+}
 
-      position++;
-    }
+static void
+glade_project_model_get_iter_for_object (GladeProject *project,
+                                         GObject *object,
+                                         GtkTreeIter *iter)
+{
+  g_assert (object);
 
-  if (!loadable)
-    glade_util_ui_message (glade_app_get_window (),
-                           GLADE_UI_ERROR, NULL,
-                           _("Failed to load %s.\n"
-                             "The following required catalogs are unavailable: %s"),
-                           path, string->str);
-  g_string_free (string, TRUE);
-  return loadable;
+  iter->stamp = project->priv->stamp;
+  iter->user_data = object;
 }
 
-static gchar *
-glade_project_read_resource_path_from_comment (GladeXmlNode *comment)
+static GtkTreeModelFlags
+glade_project_model_get_flags (GtkTreeModel *model)
 {
-  gchar *value, buffer[FILENAME_MAX], *path = NULL;
+  return 0;
+}
 
-  if (!glade_xml_node_is_comment (comment))
-    return FALSE;
+static gint
+glade_project_model_get_n_columns (GtkTreeModel *model)
+{
+  return GLADE_PROJECT_MODEL_N_COLUMNS;
+}
 
-  value = glade_xml_get_content (comment);
-  if (value &&
-      !strncmp (" interface-local-resource-path", value,
-                strlen (" interface-local-resource-path")))
+static GType
+glade_project_model_get_column_type (GtkTreeModel *model, gint column)
+{
+  switch (column)
     {
-      if (sscanf (value, " interface-local-resource-path %s", buffer) == 1)
-        path = g_strdup (buffer);
+      case GLADE_PROJECT_MODEL_COLUMN_ICON_NAME:
+        return G_TYPE_STRING;
+      case GLADE_PROJECT_MODEL_COLUMN_NAME:
+        return G_TYPE_STRING;
+      case GLADE_PROJECT_MODEL_COLUMN_TYPE_NAME:
+        return G_TYPE_STRING;
+      case GLADE_PROJECT_MODEL_COLUMN_OBJECT:
+        return G_TYPE_OBJECT;
+      case GLADE_PROJECT_MODEL_COLUMN_MISC:
+        return G_TYPE_STRING;
+      case GLADE_PROJECT_MODEL_COLUMN_WARNING:
+        return G_TYPE_STRING;
+      default:
+        g_assert_not_reached ();
+        return G_TYPE_NONE;
     }
-  g_free (value);
-
-  return path;
 }
 
-static void
-update_project_for_resource_path (GladeProject *project)
+static gboolean
+glade_project_model_get_iter (GtkTreeModel *model,
+                              GtkTreeIter *iter,
+                              GtkTreePath *path)
 {
-  GladeWidget *widget;
-  GladeProperty *property;
-  GList *l, *list;
+  GladeProject *project = GLADE_PROJECT (model);
+  gint         *indices = gtk_tree_path_get_indices (path);
+  gint          depth = gtk_tree_path_get_depth (path);
+  GladeWidget  *widget;
+  GObject      *object;
+  gint          i;
+  GList        *parent;
 
-  for (l = project->priv->objects; l; l = l->next)
+  if ((parent = g_list_nth (project->priv->tree, indices[0])) != NULL)
+    {
+      object = parent->data;
+      widget = glade_widget_get_from_gobject (object);
+    }
+  else
     {
+      iter->stamp = 0;
+      iter->user_data = NULL;
+      return FALSE;
+    }
 
-      widget = glade_widget_get_from_gobject (l->data);
+  for (i = 1; i < depth; i++)
+    {
+      object = glade_project_nth_child (project, widget, indices[i]);
 
-      for (list = glade_widget_get_properties (widget); list; list = list->next)
+      if (!object)
         {
-          GladePropertyClass *klass;
-          GParamSpec         *pspec;
+          iter->stamp = 0;
+          iter->user_data = NULL;
+          return FALSE;
+        }
 
-          property = list->data;
-          klass    = glade_property_get_class (property);
-          pspec    = glade_property_class_get_pspec (klass);
+      widget = glade_widget_get_from_gobject (object);
+    }
 
-          /* XXX We should have a "resource" flag on properties that need
-           *   to be loaded from the resource path, but that would require
-           * that they can serialize both ways (custom properties are only
-                                                * required to generate unique strings for value comparisons).
-                                                  */
-          if (pspec->value_type == GDK_TYPE_PIXBUF)
-            {
-              GValue *value;
-              gchar  *string;
-
-              string = glade_property_make_string (property);
-              value  = glade_property_class_make_gvalue_from_string (klass, string, project);
-
-              glade_property_set_value (property, value);
-
-              g_value_unset (value);
-              g_free (value);
-              g_free (string);
-            }
-        }
+  if (object)
+    {
+      glade_project_model_get_iter_for_object (project, object, iter);
+      return TRUE;
+    }
+  else
+    {
+      iter->stamp = 0;
+      iter->user_data = NULL;
+      return FALSE;
     }
 }
 
-
-/* This function assumes ownership of 'path'. */
-static void
-glade_project_set_resource_path (GladeProject *project, gchar *path)
+static GtkTreePath *
+glade_project_model_get_path (GtkTreeModel *model, GtkTreeIter *iter)
 {
-  g_free (project->priv->resource_path);
-  project->priv->resource_path = path;
+  GladeProject *project = GLADE_PROJECT (model);
+  GtkTreePath  *path;
+  GObject      *object;
+  GladeWidget  *widget;
+  GladeWidget  *toplevel;
+  GladeWidget  *parent;
+  GList        *top;
 
-  update_project_for_resource_path (project);
-  update_prefs_for_resource_path (project);
-}
+  g_return_val_if_fail (VALID_ITER (project, iter), NULL);
 
-static void
-glade_project_read_resource_path (GladeProject *project,
-                                  GladeXmlNode *root_node)
-{
-  GladeXmlNode *node;
-  gchar *path = NULL;
+  object   = iter->user_data;
+  widget   = glade_widget_get_from_gobject (object);
+  toplevel = glade_widget_get_toplevel (widget);
+  parent   = widget;
 
-  for (node = glade_xml_node_get_children_with_comments (root_node);
-       node; node = glade_xml_node_next_with_comments (node))
+  path = gtk_tree_path_new ();
+
+  while ((parent = glade_widget_get_parent (widget)) != NULL)
     {
-      /* Skip non "requires" tags */
-      if ((path = glade_project_read_resource_path_from_comment (node)) != NULL)
-        break;
-    }
+      gint position;
 
-  glade_project_set_resource_path (project, path);
-}
+      if ((position = glade_project_child_position (project, parent, 
+                                                    glade_widget_get_object (widget))) < 0)
+        gtk_tree_path_prepend_index (path, 0);
+      else
+        gtk_tree_path_prepend_index (path, position);
 
+      widget = parent;
+    }
 
-static void
-glade_project_read_comment (GladeProject *project, GladeXmlDoc *doc)
-{
-  /* TODO Write me !! Find out how to extract root level comments 
-   * with libxml2 !!! 
-   */
-}
+  /* Get the index for the top-level list */
+  top = g_list_find (project->priv->tree, glade_widget_get_object (toplevel));
 
+  /* While the project is disposing widgets are unparented and sometimes no longer in the tree */
+  if (top)
+    gtk_tree_path_prepend_index (path, g_list_position (project->priv->tree, top));
+  else
+    gtk_tree_path_prepend_index (path, 0);
+  
+  return path;
+}
 
-typedef struct
+static void
+glade_project_model_get_value (GtkTreeModel *model,
+                               GtkTreeIter *iter,
+                               gint column,
+                               GValue *value)
 {
+  GObject *object;
   GladeWidget *widget;
-  gint major;
-  gint minor;
-} VersionData;
+  GladeProperty *ref_prop;
+  gchar *str = NULL, *child_type;
 
-static void
-glade_project_introspect_signal_versions (GladeSignal *signal,
-                                          VersionData *data)
-{
-  GladeSignalClass   *signal_class;
-  GladeWidgetAdaptor *adaptor;
-  gchar              *catalog = NULL;
-  gboolean            is_gtk_adaptor = FALSE;
+  g_return_if_fail (VALID_ITER (model, iter));
 
-  signal_class =
-    glade_widget_adaptor_get_signal_class (glade_widget_get_adaptor (data->widget), 
-                                           glade_signal_get_name (signal));
+  object = iter->user_data;
+  widget = glade_widget_get_from_gobject (object);
 
-  /*  unknown signal... can it happen ? */
-  if (!signal_class) 
-    return;
+  value = g_value_init (value,
+                        glade_project_model_get_column_type (model, column));
 
-  adaptor = glade_signal_class_get_adaptor (signal_class);
+  switch (column)
+    {
+      case GLADE_PROJECT_MODEL_COLUMN_ICON_NAME:
+        g_object_get (glade_widget_get_adaptor (widget), "icon-name", &str, NULL);
+        g_value_take_string (value, str);
+        break;
+      case GLADE_PROJECT_MODEL_COLUMN_NAME:
+        g_value_set_string (value, glade_widget_get_name (widget));
+        break;
+      case GLADE_PROJECT_MODEL_COLUMN_TYPE_NAME:
+        g_value_set_static_string (value, G_OBJECT_TYPE_NAME (object));
+        break;
+      case GLADE_PROJECT_MODEL_COLUMN_OBJECT:
+        g_value_set_object (value, object);
+        break;
+      case GLADE_PROJECT_MODEL_COLUMN_MISC:
+        /* special child type / internal child */
+        if (glade_widget_get_internal (widget) != NULL)
+          str = g_strdup_printf (_("(internal %s)"),
+                                 glade_widget_get_internal (widget));
+        else if ((child_type =
+                  g_object_get_data (glade_widget_get_object (widget),
+                                     "special-child-type")) != NULL)
+          str = g_strdup_printf (_("(%s child)"), child_type);
+        else if (glade_widget_get_is_composite (widget))
+          str = g_strdup_printf (_("(template)"));
+        else if ((ref_prop = 
+                  glade_widget_get_parentless_widget_ref (widget)) != NULL)
+        {
+          GladePropertyClass *pclass     = glade_property_get_class (ref_prop);
+          GladeWidget        *ref_widget = glade_property_get_widget (ref_prop);
 
-  /* Check if the signal comes from a GTK+ widget class */
-  g_object_get (adaptor, "catalog", &catalog, NULL);
-  if (strcmp (catalog, "gtk+") == 0)
-    is_gtk_adaptor = TRUE;
-  g_free (catalog);
+          /* translators: refers to a property named '%s' of widget '%s' */
+          str = g_strdup_printf (_("(%s of %s)"), 
+                                 glade_property_class_get_name (pclass),
+                                 glade_widget_get_name (ref_widget));
+        }
 
-  if (is_gtk_adaptor && 
-      !GSC_VERSION_CHECK (signal_class, data->major, data->minor))
-    {
-      data->major = glade_signal_class_since_major (signal_class);
-      data->minor = glade_signal_class_since_minor (signal_class);
+        g_value_take_string (value, str);
+        break;
+      case GLADE_PROJECT_MODEL_COLUMN_WARNING:
+        g_value_set_string (value, glade_widget_support_warning (widget));
+       break;
+
+      default:
+        g_assert_not_reached ();
     }
 }
 
-static void
-glade_project_introspect_gtk_version (GladeProject *project)
+static gboolean
+glade_project_model_iter_next (GtkTreeModel *model, GtkTreeIter *iter)
 {
+  GladeProject *project = GLADE_PROJECT (model);
+  GObject *object = iter->user_data;
   GladeWidget *widget;
-  GList *list, *l;
-  gint target_major = 2, target_minor = 12;
+  GladeWidget *parent;
+  GList *children;
+  GList *child;
+  GList *next;
+  gboolean retval = FALSE;
 
-  for (list = project->priv->objects; list; list = list->next)
-    {
-      gboolean is_gtk_adaptor = FALSE;
-      gchar *catalog = NULL;
-      VersionData data = { 0, };
-      GList *signals;
+  g_return_val_if_fail (VALID_ITER (project, iter), FALSE);
 
-      widget = glade_widget_get_from_gobject (list->data);
+  widget = glade_widget_get_from_gobject (object);
+  parent = glade_widget_get_parent (widget);
 
-      /* Check if its a GTK+ widget class */
-      g_object_get (glade_widget_get_adaptor (widget), "catalog", &catalog, NULL);
-      if (strcmp (catalog, "gtk+") == 0)
-        is_gtk_adaptor = TRUE;
-      g_free (catalog);
+  if (parent)
+    {
+      children = glade_widget_get_children (parent);
+    }
+  else
+    {
+      children = project->priv->tree;
+    }
 
-      /* Check widget class version */
-      if (is_gtk_adaptor &&
-          !GWA_VERSION_CHECK (glade_widget_get_adaptor (widget), target_major, target_minor))
+  child = g_list_find (children, object);
+  if (child)
+    {
+      /* Get the next child that is actually in the project */
+      for (next = child->next; next; next = next->next)
         {
-          target_major = GWA_VERSION_SINCE_MAJOR (glade_widget_get_adaptor (widget));
-          target_minor = GWA_VERSION_SINCE_MINOR (glade_widget_get_adaptor (widget));
+          GObject *object = next->data;
+
+          if (glade_project_has_object (project, object))
+            break;
         }
 
-      /* Check all properties */
-      for (l = glade_widget_get_properties (widget); l; l = l->next)
+      if (next)
         {
-          GladeProperty *property = l->data;
-          GladePropertyClass *pclass = glade_property_get_class (property);
-          GladeWidgetAdaptor *prop_adaptor, *adaptor;
-          GParamSpec         *pspec;
+          glade_project_model_get_iter_for_object (project, next->data, iter);
+          retval = TRUE;
+        }
+    }
+  if (children != project->priv->tree)
+    g_list_free (children);
 
-          /* Unset properties ofcourse dont count... */
-          if (glade_property_original_default (property))
-            continue;
+  return retval;
+}
 
-          /* Check if this property originates from a GTK+ widget class */
-          pspec        = glade_property_class_get_pspec (pclass);
-          prop_adaptor = glade_property_class_get_adaptor (pclass);
-          adaptor      = glade_widget_adaptor_from_pspec (prop_adaptor, pspec);
+static gboolean
+glade_project_model_iter_has_child (GtkTreeModel *model, GtkTreeIter *iter)
+{
+  GladeProject *project = GLADE_PROJECT (model);
+  GladeWidget  *widget;
 
-          catalog = NULL;
-          is_gtk_adaptor = FALSE;
-          g_object_get (adaptor, "catalog", &catalog, NULL);
-          if (strcmp (catalog, "gtk+") == 0)
-            is_gtk_adaptor = TRUE;
-          g_free (catalog);
+  g_return_val_if_fail (VALID_ITER (model, iter), FALSE);
 
-          /* Check GTK+ property class versions */
-          if (is_gtk_adaptor &&
-              !GPC_VERSION_CHECK (pclass, target_major, target_minor))
-            {
-              target_major = glade_property_class_since_major (pclass);
-              target_minor = glade_property_class_since_minor (pclass);
-            }
-        }
-
-      /* Check all signal versions here */
-      data.widget = widget;
-      data.major = target_major;
-      data.minor = target_minor;
-
-      signals = glade_widget_get_signal_list (widget);
-      g_list_foreach (signals, (GFunc)glade_project_introspect_signal_versions, &data);
-      g_list_free (signals);
-
-      if (target_major < data.major)
-        target_major = data.major;
+  widget = glade_widget_get_from_gobject (iter->user_data);
 
-      if (target_minor < data.minor)
-        target_minor = data.minor;
-    }
+  if (glade_project_count_children (project, widget) > 0)
+    return TRUE;
 
-  glade_project_set_target_version (project, "gtk+", target_major,
-                                    target_minor);
+  return FALSE;
 }
 
-
 static gint
-glade_project_count_xml_objects (GladeProject *project,
-                                 GladeXmlNode *root,
-                                 gint count)
+glade_project_model_iter_n_children (GtkTreeModel *model, GtkTreeIter *iter)
 {
-  GladeXmlNode *node;
+  GladeProject *project = GLADE_PROJECT (model);
 
-  for (node = glade_xml_node_get_children (root);
-       node; node = glade_xml_node_next (node))
+  g_return_val_if_fail (iter == NULL || VALID_ITER (project, iter), 0);
+
+  if (iter)
     {
-      if (glade_xml_node_verify_silent (node, GLADE_XML_TAG_WIDGET) ||
-         glade_xml_node_verify_silent (node, GLADE_XML_TAG_TEMPLATE))
-        count = glade_project_count_xml_objects (project, node, ++count);
-      else if (glade_xml_node_verify_silent (node, GLADE_XML_TAG_CHILD))
-        count = glade_project_count_xml_objects (project, node, count);
-    }
-  return count;
-}
+      GladeWidget *widget = glade_widget_get_from_gobject (iter->user_data);
 
-void
-glade_project_cancel_load (GladeProject *project)
-{
-  g_return_if_fail (GLADE_IS_PROJECT (project));
+      return glade_project_count_children (project, widget);
+    }
 
-  project->priv->load_cancel = TRUE;
+  return g_list_length (project->priv->tree);
 }
 
-gboolean
-glade_project_load_cancelled (GladeProject *project)
+static gboolean
+glade_project_model_iter_nth_child (GtkTreeModel *model,
+                                    GtkTreeIter *iter,
+                                    GtkTreeIter *parent,
+                                    gint nth)
 {
-  g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
+  GladeProject *project = GLADE_PROJECT (model);
+  GObject      *object = NULL;
 
-  return project->priv->load_cancel;
-}
+  g_return_val_if_fail (parent == NULL || VALID_ITER (project, parent), FALSE);
 
-void
-glade_project_push_progress (GladeProject *project)
-{
-  g_return_if_fail (GLADE_IS_PROJECT (project));
+  if (parent != NULL)
+    {
+      GObject     *obj    = parent->user_data;
+      GladeWidget *widget = glade_widget_get_from_gobject (obj);
 
-  project->priv->progress_step++;
+      object = glade_project_nth_child (project, widget, nth);
+    }
+  else if (project->priv->tree)
+    {
+      GList *child = g_list_nth (project->priv->tree, nth);
 
-  g_signal_emit (project, glade_project_signals[LOAD_PROGRESS], 0,
-                 project->priv->progress_full, project->priv->progress_step);
-}
+      if (child)
+        object = child->data;
+    }
+
+  if (object)
+    {
+      glade_project_model_get_iter_for_object (project, object, iter);
+      return TRUE;
+    }
 
+  iter->stamp     = 0;
+  iter->user_data = NULL;
 
-/* translators: refers to project name '%s' that targets gtk version '%d.%d' */
-#define PROJECT_TARGET_DIALOG_TITLE_FMT _("%s targets Gtk+ %d.%d")
+  return FALSE;
+}
 
-static void
-glade_project_check_target_version (GladeProject *project)
+static gboolean
+glade_project_model_iter_children (GtkTreeModel *model,
+                                   GtkTreeIter *iter,
+                                   GtkTreeIter *parent)
 {
-  GladeProjectPrivate *priv;
-  GHashTable *unknown_classes;
-  gint unknown_objects;
-  gint major, minor;
-  GtkWidget *dialog;
-  GString *text;
-  GList *l;
-
-  glade_project_get_target_version (project, "gtk+", &major, &minor);
-    
-  /* Glade >= 3.10 only targets Gtk 3 */
-  if (major >= 3) return;
+  GladeProject *project = GLADE_PROJECT (model);
+  GObject      *object  = NULL;
 
-  priv = project->priv;
-  unknown_classes = g_hash_table_new (g_str_hash, g_str_equal);
-  unknown_objects = 0;
+  g_return_val_if_fail (parent == NULL || VALID_ITER (project, parent), FALSE);
 
-  for (l = priv->objects; l; l = g_list_next (l))
+  if (parent)
     {
-      if (GLADE_IS_OBJECT_STUB (l->data))
-        {
-          gchar *type;
-          g_object_get (l->data, "object-type", &type, NULL);
-          g_hash_table_insert (unknown_classes, type, NULL);
-          unknown_objects++;
-        }
+      GladeWidget *widget = glade_widget_get_from_gobject (parent->user_data);
+
+      object = glade_project_nth_child (project, widget, 0);
     }
+  else if (project->priv->tree)
+    object = project->priv->tree->data;
 
-  if (unknown_objects)
+  if (object)
     {
-      GList *classes = g_hash_table_get_keys (unknown_classes);
-
-      if (unknown_objects == 1)
-        {
-          text = g_string_new (_("Specially because there is an object that can not be build with type "));
-        }
-      else
-        {
-          text = g_string_new ("");
-          g_string_printf (text, _("Specially because there are %d objects that can not be build with types 
"),
-                           unknown_objects);
-        }
+      glade_project_model_get_iter_for_object (project, object, iter);
+      return TRUE;
+    }
 
-      for (l = classes; l; l = g_list_next (l))
-        {
-          if (g_list_previous (l))
-            g_string_append (text, (g_list_next (l)) ? ", " : _(" and "));
-          
-          g_string_append (text, l->data);
-        }
+  iter->stamp = 0;
+  iter->user_data = NULL;
+  return FALSE;
+}
 
-      g_list_free (classes);
-    }
-  else 
-    text = NULL;
+static gboolean
+glade_project_model_iter_parent (GtkTreeModel *model,
+                                 GtkTreeIter *iter,
+                                 GtkTreeIter *child)
+{
+  GladeProject *project = GLADE_PROJECT (model);
+  GladeWidget *widget;
+  GladeWidget *parent;
 
-  dialog = gtk_message_dialog_new (GTK_WINDOW (glade_app_get_window ()),
-                                   GTK_DIALOG_DESTROY_WITH_PARENT,
-                                   GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
-                                   PROJECT_TARGET_DIALOG_TITLE_FMT,
-                                   glade_project_get_name (project),
-                                   major, minor);
+  g_return_val_if_fail (VALID_ITER (project, child), FALSE);
 
-  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
-                                            _("But this version of Glade is for GTK+ 3 only.\n"
-                                              "Make sure you can run this project with Glade 3.8 with no 
deprecated widgets first.\n"
-                                              "%s"), (text) ? text->str : "");
+  widget = glade_widget_get_from_gobject (child->user_data);
+  parent = glade_widget_get_parent (widget);
 
-  gtk_dialog_run (GTK_DIALOG (dialog));
-  gtk_widget_destroy (dialog);
+  if (parent && 
+      glade_project_has_object (project, glade_widget_get_object (parent)))
+    {
+      glade_project_model_get_iter_for_object (project,
+                                               glade_widget_get_object (parent),
+                                               iter);
+      return TRUE;
+    }
 
-  glade_project_set_target_version (project, "gtk+", 3, 0);
+  iter->stamp = 0;
+  iter->user_data = NULL;
 
-  g_hash_table_destroy (unknown_classes);
-  if (text) g_string_free (text, TRUE);
+  return FALSE;
 }
 
-static gchar *
-glade_project_autosave_name (const gchar *path)
+static void
+glade_project_model_iface_init (GtkTreeModelIface *iface)
 {
-  gchar *basename, *dirname, *autoname;
-  gchar *autosave_name;
-
-  basename = g_path_get_basename (path);
-  dirname = g_path_get_dirname (path);
-
-  autoname = g_strdup_printf ("#%s#", basename);
-  autosave_name = g_build_filename (dirname, autoname, NULL);
+  iface->get_flags = glade_project_model_get_flags;
+  iface->get_column_type = glade_project_model_get_column_type;
+  iface->get_n_columns = glade_project_model_get_n_columns;
+  iface->get_iter = glade_project_model_get_iter;
+  iface->get_path = glade_project_model_get_path;
+  iface->get_value = glade_project_model_get_value;
+  iface->iter_next = glade_project_model_iter_next;
+  iface->iter_children = glade_project_model_iter_children;
+  iface->iter_has_child = glade_project_model_iter_has_child;
+  iface->iter_n_children = glade_project_model_iter_n_children;
+  iface->iter_nth_child = glade_project_model_iter_nth_child;
+  iface->iter_parent = glade_project_model_iter_parent;
+}
 
-  g_free (basename);
-  g_free (dirname);
-  g_free (autoname);
+/*******************************************************************
+                    Loading project code here
+ *******************************************************************/
 
-  return autosave_name;
+/**
+ * glade_project_new:
+ *
+ * Creates a new #GladeProject.
+ *
+ * Returns: a new #GladeProject
+ */
+GladeProject *
+glade_project_new (void)
+{
+  GladeProject *project = g_object_new (GLADE_TYPE_PROJECT, NULL);
+  return project;
 }
 
-static gboolean
-glade_project_load_internal (GladeProject *project)
-{
-  GladeProjectPrivate *priv = project->priv;
-  GladeXmlContext *context;
-  GladeXmlDoc *doc;
-  GladeXmlNode *root;
-  GladeXmlNode *node;
-  GladeWidget *widget;
-  gboolean has_gtk_dep = FALSE;
-  gchar *domain;
-  gint count;
-  gchar *autosave_path;
-  time_t mtime, autosave_mtime;
-  gchar *load_path = NULL;
-
-  /* Check if an autosave is more recent then the specified file */
-  autosave_path = glade_project_autosave_name (priv->path);
-  autosave_mtime = glade_util_get_file_mtime (autosave_path, NULL);
-  mtime = glade_util_get_file_mtime (priv->path, NULL);
+/* Called when finishing loading a glade file to resolve object type properties
+ */
+static void
+glade_project_fix_object_props (GladeProject *project)
+{
+  GList *l, *ll, *objects;
+  GValue *value;
+  GladeWidget *gwidget;
+  GladeProperty *property;
+  gchar *txt;
 
-  if (autosave_mtime > mtime)
+  objects = g_list_copy (project->priv->objects);
+  for (l = objects; l; l = l->next)
     {
-      gchar *display_name;
+      gwidget = glade_widget_get_from_gobject (l->data);
 
-      display_name = glade_project_get_name (project);
+      for (ll = glade_widget_get_properties (gwidget); ll; ll = ll->next)
+        {
+          GladePropertyClass *klass;
 
-      if (glade_util_ui_message (glade_app_get_window (),
-                                GLADE_UI_YES_OR_NO, NULL,
-                                _("An automatically saved version of `%s' is more recent\n\n"
-                                  "Would you like to load the autosave version instead ?"),
-                                display_name))
-       {
-         mtime = autosave_mtime;
-         load_path = g_strdup (autosave_path);
-       }
-      g_free (display_name);
-    }
+          property = GLADE_PROPERTY (ll->data);
+          klass    = glade_property_get_class (property);
 
-  g_free (autosave_path);
+          if (glade_property_class_is_object (klass) &&
+              (txt = g_object_get_data (G_OBJECT (property),
+                                        "glade-loaded-object")) != NULL)
+            {
+              /* Parse the object list and set the property to it
+               * (this magicly works for both objects & object lists)
+               */
+              value = glade_property_class_make_gvalue_from_string (klass, txt, project);
 
-  priv->selection = NULL;
-  priv->objects = NULL;
-  priv->loading = TRUE;
+              glade_property_set_value (property, value);
 
-  /* get the context & root node of the catalog file */
-  if (!(context =
-        glade_xml_context_new_from_path (load_path ? load_path : priv->path, NULL, NULL)))
-    {
-      g_warning ("Couldn't open glade file [%s].", load_path ? load_path : priv->path);
-      g_free (load_path);
-      priv->loading = FALSE;
-      return FALSE;
-    }
+              g_value_unset (value);
+              g_free (value);
 
-  priv->mtime = mtime;
+              g_object_set_data (G_OBJECT (property),
+                                 "glade-loaded-object", NULL);
+            }
+        }
+    }
+  g_list_free (objects);
+}
 
-  doc = glade_xml_context_get_doc (context);
-  root = glade_xml_doc_get_root (doc);
+static void
+glade_project_fix_template (GladeProject *project)
+{
+  GList *l;
+  gboolean composite = FALSE;
 
-  if (!glade_xml_node_verify_silent (root, GLADE_XML_TAG_PROJECT))
+  for (l = project->priv->tree; l; l = l->next)
     {
-      g_warning ("Couldnt recognize GtkBuilder xml, skipping %s",
-                 load_path ? load_path : priv->path);
-      glade_xml_context_free (context);
-      g_free (load_path);
-      priv->loading = FALSE;
-      return FALSE;
-    }
-
-  /* Emit "parse-began" signal */
-  g_signal_emit (project, glade_project_signals[PARSE_BEGAN], 0);
+      GObject     *obj = l->data;
+      GladeWidget *gwidget;
 
-  if ((domain = glade_xml_get_property_string (root, GLADE_TAG_DOMAIN)))
-    glade_project_set_translation_domain (project, domain);
+      gwidget   = glade_widget_get_from_gobject (obj);
+      composite = glade_widget_get_is_composite (gwidget);
 
-  /* XXX Need to load project->priv->comment ! */
-  glade_project_read_comment (project, doc);
+      if (composite)
+        {
+         glade_project_set_template (project, gwidget);
+         break;
+        }
+    }
+}
 
-  /* Read requieres, and do not abort load if there are missing catalog since
-   * GladeObjectStub is created to keep the original xml for unknown object classes
-   */
-  glade_project_read_requires (project, root, load_path ? load_path : priv->path, &has_gtk_dep);
+static gchar *
+glade_project_read_requires_from_comment (GladeXmlNode *comment,
+                                          guint16 *major, guint16 *minor)
+{
+  gint maj, min;
+  gchar *value, buffer[256];
+  gchar *required_lib = NULL;
 
-  glade_project_read_resource_path (project, root);
+  if (!glade_xml_node_is_comment (comment))
+    return NULL;
 
-  /* Launch a dialog if it's going to take enough time to be
-   * worth showing at all */
-  count = glade_project_count_xml_objects (project, root, 0);
-  priv->progress_full = count;
-  priv->progress_step = 0;
+  value = glade_xml_get_content (comment);
 
-  for (node = glade_xml_node_get_children (root);
-       node; node = glade_xml_node_next (node))
+  if (value &&
+      !strncmp (" interface-requires", value, strlen (" interface-requires")))
     {
-      /* Skip "requires" tags */
-      if (!(glade_xml_node_verify_silent (node, GLADE_XML_TAG_WIDGET) ||
-           glade_xml_node_verify_silent (node, GLADE_XML_TAG_TEMPLATE)))
-        continue;
+      if (sscanf (value, " interface-requires %s %d.%d", buffer, &maj, &min) == 3)
+        {
+          if (major)
+            *major = maj;
+          if (minor)
+            *minor = min;
+          required_lib = g_strdup (buffer);
+        }
+    }
+  g_free (value);
 
-      if ((widget = glade_widget_read (project, NULL, node, NULL)) != NULL)
-        glade_project_add_object (project, glade_widget_get_object (widget));
+  return required_lib;
+}
 
-      if (priv->load_cancel)
-        break;
-    }
 
-  /* Finished with the xml context */
-  glade_xml_context_free (context);
+static gboolean
+glade_project_read_requires (GladeProject *project,
+                             GladeXmlNode *root_node,
+                             const gchar *path, gboolean *has_gtk_dep)
+{
 
-  if (priv->load_cancel)
+  GString *string = g_string_new (NULL);
+  GladeXmlNode *node;
+  gchar *required_lib = NULL;
+  gboolean loadable = TRUE;
+  guint16 major, minor;
+  gint position = 0;
+
+  for (node = glade_xml_node_get_children_with_comments (root_node);
+       node; node = glade_xml_node_next_with_comments (node))
     {
-      priv->loading = FALSE;
-      g_free (load_path);
-      return FALSE;
-    }
+      /* Skip non "requires" tags */
+      if (!(glade_xml_node_verify_silent (node, GLADE_XML_TAG_REQUIRES) ||
+            (required_lib =
+             glade_project_read_requires_from_comment (node, &major, &minor))))
+        continue;
 
-  if (!has_gtk_dep)
-    glade_project_introspect_gtk_version (project);
+      if (!required_lib)
+        {
+          required_lib =
+              glade_xml_get_property_string_required (node, GLADE_XML_TAG_LIB,
+                                                      NULL);
+          glade_xml_get_property_version (node, GLADE_XML_TAG_VERSION,
+                                          &major, &minor);
+        }
 
-  if (glade_util_file_is_writeable (priv->path) == FALSE)
-    glade_project_set_readonly (project, TRUE);
+      if (!required_lib)
+        continue;
 
-  /* Now we have to loop over all the object properties
-   * and fix'em all ('cause they probably weren't found)
-   */
-  glade_project_fix_object_props (project);
+      /* Dont mention gtk+ as a required lib in 
+       * the generated glade file
+       */
+      if (!glade_catalog_is_loaded (required_lib))
+        {
+          CatalogInfo *data = g_new0(CatalogInfo, 1);
+          
+          data->catalog = required_lib;
+          data->position = position;
 
-  glade_project_fix_template (project);
+          /* Keep a list of unknown catalogs to avoid loosing the requirement */
+          project->priv->unknown_catalogs = g_list_append (project->priv->unknown_catalogs,
+                                                           data);
+          /* Also keep the version */
+          glade_project_set_target_version (project, required_lib, major, minor);
 
-  /* Emit "parse-finished" signal */
-  g_signal_emit (project, glade_project_signals[PARSE_FINISHED], 0);
+          if (!loadable)
+            g_string_append (string, ", ");
 
-  /* Reset project status here too so that you get a clean
-   * slate after calling glade_project_open().
-   */
-  priv->modified = FALSE;
-  priv->loading = FALSE;
+          g_string_append (string, required_lib);
+          loadable = FALSE;
+        }
+      else
+        {
+          if (has_gtk_dep && strcmp (required_lib, "gtk+") == 0)
+            *has_gtk_dep = TRUE;
 
-  /* Update ui with versioning info
-   */
-  glade_project_verify_project_for_ui (project);
+          glade_project_set_target_version
+              (project, required_lib, major, minor);
+          g_free (required_lib);
+        }
 
-  glade_project_check_target_version (project);
-  
-  return TRUE;
+      position++;
+    }
 
+  if (!loadable)
+    glade_util_ui_message (glade_app_get_window (),
+                           GLADE_UI_ERROR, NULL,
+                           _("Failed to load %s.\n"
+                             "The following required catalogs are unavailable: %s"),
+                           path, string->str);
+  g_string_free (string, TRUE);
+  return loadable;
 }
 
-static void
-glade_project_update_properties_title (GladeProject *project)
+static gchar *
+glade_project_read_resource_path_from_comment (GladeXmlNode *comment)
 {
-  gchar *name, *title;
+  gchar *value, buffer[FILENAME_MAX], *path = NULL;
 
-  /* Update prefs dialogs here... */
-  name = glade_project_get_name (project);
-  title = g_strdup_printf (_("%s document properties"), name);
-  gtk_window_set_title (GTK_WINDOW (project->priv->prefs_dialog), title);
-  g_free (title);
-  g_free (name); 
+  if (!glade_xml_node_is_comment (comment))
+    return FALSE;
+
+  value = glade_xml_get_content (comment);
+  if (value &&
+      !strncmp (" interface-local-resource-path", value,
+                strlen (" interface-local-resource-path")))
+    {
+      if (sscanf (value, " interface-local-resource-path %s", buffer) == 1)
+        path = g_strdup (buffer);
+    }
+  g_free (value);
+
+  return path;
 }
 
-gboolean
-glade_project_load_from_file (GladeProject *project, const gchar *path)
+static void
+update_project_for_resource_path (GladeProject *project)
 {
-  gboolean retval;
-
-  g_return_val_if_fail (path != NULL, FALSE);
-  g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
+  GladeWidget *widget;
+  GladeProperty *property;
+  GList *l, *list;
 
-  project->priv->path = glade_util_canonical_path (path);
-  g_object_notify_by_pspec (G_OBJECT (project), properties[PROP_PATH]);
+  for (l = project->priv->objects; l; l = l->next)
+    {
 
-  if ((retval = glade_project_load_internal (project)))
-    glade_project_update_properties_title (project);
+      widget = glade_widget_get_from_gobject (l->data);
 
-  return retval;
-}
+      for (list = glade_widget_get_properties (widget); list; list = list->next)
+        {
+          GladePropertyClass *klass;
+          GParamSpec         *pspec;
 
-/**
- * glade_project_load:
- * @path:
- * 
- * Opens a project at the given path.
- *
- * Returns: a new #GladeProject for the opened project on success, %NULL on 
- *          failure
- */
-GladeProject *
-glade_project_load (const gchar *path)
-{
-  GladeProject *project;
+          property = list->data;
+          klass    = glade_property_get_class (property);
+          pspec    = glade_property_class_get_pspec (klass);
 
-  g_return_val_if_fail (path != NULL, NULL);
+          /* XXX We should have a "resource" flag on properties that need
+           *   to be loaded from the resource path, but that would require
+           * that they can serialize both ways (custom properties are only
+                                                * required to generate unique strings for value comparisons).
+                                                  */
+          if (pspec->value_type == GDK_TYPE_PIXBUF)
+            {
+              GValue *value;
+              gchar  *string;
 
-  project = g_object_new (GLADE_TYPE_PROJECT, NULL);
+              string = glade_property_make_string (property);
+              value  = glade_property_class_make_gvalue_from_string (klass, string, project);
 
-  project->priv->path = glade_util_canonical_path (path);
+              glade_property_set_value (property, value);
 
-  if (glade_project_load_internal (project))
-    {
-      glade_project_update_properties_title (project);
-      return project;
-    }
-  else
-    {
-      g_object_unref (project);
-      return NULL;
+              g_value_unset (value);
+              g_free (value);
+              g_free (string);
+            }
+        }
     }
 }
 
-/*******************************************************************
-                    Writing project code here
- *******************************************************************/
+void
+glade_project_set_resource_path (GladeProject *project, const gchar *path)
+{
+  g_return_if_fail (GLADE_IS_PROJECT (project));
 
-#define GLADE_XML_COMMENT "Generated with "PACKAGE_NAME
+  if (g_strcmp0 (project->priv->resource_path, path) != 0)
+    {
+      g_free (project->priv->resource_path);
+      project->priv->resource_path = g_strdup (path);
 
-static gchar *
-glade_project_make_comment (void)
+      update_project_for_resource_path (project);
+
+      g_object_notify_by_pspec (G_OBJECT (project), glade_project_props[PROP_RESOURCE_PATH]);
+    }
+}
+
+const gchar *
+glade_project_get_resource_path (GladeProject *project)
 {
-  time_t now = time (NULL);
-  gchar *comment;
-  comment = g_strdup_printf (GLADE_XML_COMMENT " " PACKAGE_VERSION " on %s",
-                             ctime (&now));
-  glade_util_replace (comment, '\n', ' ');
+  g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
 
-  return comment;
+  return project->priv->resource_path;
 }
 
 static void
-glade_project_update_comment (GladeProject *project)
+glade_project_read_resource_path (GladeProject *project,
+                                  GladeXmlNode *root_node)
 {
-  gchar **lines, **l, *comment = NULL;
+  GladeXmlNode *node;
+  gchar *path = NULL;
 
-  /* If project has no comment -> add the new one */
-  if (project->priv->comment == NULL)
+  for (node = glade_xml_node_get_children_with_comments (root_node);
+       node; node = glade_xml_node_next_with_comments (node))
     {
-      project->priv->comment = glade_project_make_comment ();
-      return;
+      /* Skip non "requires" tags */
+      if ((path = glade_project_read_resource_path_from_comment (node)) != NULL)
+        break;
     }
 
-  for (lines = l = g_strsplit (project->priv->comment, "\n", 0); *l; l++)
-    {
-      gchar *start;
+  glade_project_set_resource_path (project, path);
+  g_free (path);
+}
 
-      /* Ignore leading spaces */
-      for (start = *l; *start && g_ascii_isspace (*start); start++);
 
-      if (g_str_has_prefix (start, GLADE_XML_COMMENT))
-        {
-          /* This line was generated by glade -> updating... */
-          g_free (*l);
-          *l = comment = glade_project_make_comment ();
-        }
-    }
+static void
+glade_project_read_comment (GladeProject *project, GladeXmlDoc *doc)
+{
+  /* TODO Write me !! Find out how to extract root level comments 
+   * with libxml2 !!! 
+   */
+}
 
-  if (comment)
-    {
-      g_free (project->priv->comment);
-      project->priv->comment = g_strjoinv ("\n", lines);
-    }
 
-  g_strfreev (lines);
-}
+typedef struct
+{
+  GladeWidget *widget;
+  gint major;
+  gint minor;
+} VersionData;
 
 static void
-glade_project_write_required_libs (GladeProject *project,
-                                   GladeXmlContext *context,
-                                   GladeXmlNode *root)
+glade_project_introspect_signal_versions (GladeSignal *signal,
+                                          VersionData *data)
 {
-  GladeXmlNode *req_node;
-  GList *required, *list;
-  gint major, minor;
-  gchar *version;
+  GladeSignalClass   *signal_class;
+  GladeWidgetAdaptor *adaptor;
+  gchar              *catalog = NULL;
+  gboolean            is_gtk_adaptor = FALSE;
 
-  if ((required = glade_project_required_libs (project)) != NULL)
-    {
-      for (list = required; list; list = list->next)
-        {
-          glade_project_get_target_version (project, (gchar *) list->data,
-                                            &major, &minor);
+  signal_class =
+    glade_widget_adaptor_get_signal_class (glade_widget_get_adaptor (data->widget), 
+                                           glade_signal_get_name (signal));
 
-          version = g_strdup_printf ("%d.%d", major, minor);
+  /*  unknown signal... can it happen ? */
+  if (!signal_class) 
+    return;
 
-          /* Write the standard requires tag */
-          if (GLADE_GTKBUILDER_HAS_VERSIONING (major, minor))
-            {
-              req_node = glade_xml_node_new (context, GLADE_XML_TAG_REQUIRES);
-              glade_xml_node_append_child (root, req_node);
-              glade_xml_node_set_property_string (req_node,
-                                                  GLADE_XML_TAG_LIB,
-                                                  (gchar *) list->data);
-            }
-          else
-            {
-              gchar *comment = g_strdup_printf (" interface-requires %s %s ",
-                                                (gchar *) list->data, version);
-              req_node = glade_xml_node_new_comment (context, comment);
-              glade_xml_node_append_child (root, req_node);
-              g_free (comment);
-            }
+  adaptor = glade_signal_class_get_adaptor (signal_class);
 
-          glade_xml_node_set_property_string (req_node, GLADE_XML_TAG_VERSION,
-                                              version);
-          g_free (version);
+  /* Check if the signal comes from a GTK+ widget class */
+  g_object_get (adaptor, "catalog", &catalog, NULL);
+  if (strcmp (catalog, "gtk+") == 0)
+    is_gtk_adaptor = TRUE;
+  g_free (catalog);
 
-        }
-      g_list_foreach (required, (GFunc) g_free, NULL);
-      g_list_free (required);
+  if (is_gtk_adaptor && 
+      !GSC_VERSION_CHECK (signal_class, data->major, data->minor))
+    {
+      data->major = glade_signal_class_since_major (signal_class);
+      data->minor = glade_signal_class_since_minor (signal_class);
     }
 }
 
 static void
-glade_project_write_resource_path (GladeProject *project,
-                                   GladeXmlContext *context,
-                                   GladeXmlNode *root)
+glade_project_introspect_gtk_version (GladeProject *project)
 {
-  GladeXmlNode *path_node;
-  if (project->priv->resource_path)
+  GladeWidget *widget;
+  GList *list, *l;
+  gint target_major = 2, target_minor = 12;
+
+  for (list = project->priv->objects; list; list = list->next)
     {
-      gchar *comment = g_strdup_printf (" interface-local-resource-path %s ",
-                                        project->priv->resource_path);
-      path_node = glade_xml_node_new_comment (context, comment);
-      glade_xml_node_append_child (root, path_node);
-      g_free (comment);
-    }
-}
+      gboolean is_gtk_adaptor = FALSE;
+      gchar *catalog = NULL;
+      VersionData data = { 0, };
+      GList *signals;
 
-static gint
-sort_project_dependancies (GObject *a, GObject *b)
-{
-  GladeWidget *ga, *gb;
+      widget = glade_widget_get_from_gobject (list->data);
 
-  ga = glade_widget_get_from_gobject (a);
-  gb = glade_widget_get_from_gobject (b);
+      /* Check if its a GTK+ widget class */
+      g_object_get (glade_widget_get_adaptor (widget), "catalog", &catalog, NULL);
+      if (strcmp (catalog, "gtk+") == 0)
+        is_gtk_adaptor = TRUE;
+      g_free (catalog);
 
-  if (glade_widget_depends (ga, gb))
-    return 1;
-  else if (glade_widget_depends (gb, ga))
-    return -1;
-  else
-    return strcmp (glade_widget_get_name (ga), glade_widget_get_name (gb));
-}
-
-static GladeXmlContext *
-glade_project_write (GladeProject *project)
-{
-  GladeProjectPrivate *priv = project->priv;
-  GladeXmlContext *context;
-  GladeXmlDoc *doc;
-  GladeXmlNode *root;           /* *comment_node; */
-  GList *list;
-  GList *toplevels;
+      /* Check widget class version */
+      if (is_gtk_adaptor &&
+          !GWA_VERSION_CHECK (glade_widget_get_adaptor (widget), target_major, target_minor))
+        {
+          target_major = GWA_VERSION_SINCE_MAJOR (glade_widget_get_adaptor (widget));
+          target_minor = GWA_VERSION_SINCE_MINOR (glade_widget_get_adaptor (widget));
+        }
 
-  doc = glade_xml_doc_new ();
-  context = glade_xml_context_new (doc, NULL);
-  root = glade_xml_node_new (context, GLADE_XML_TAG_PROJECT);
-  glade_xml_doc_set_root (doc, root);
+      /* Check all properties */
+      for (l = glade_widget_get_properties (widget); l; l = l->next)
+        {
+          GladeProperty *property = l->data;
+          GladePropertyClass *pclass = glade_property_get_class (property);
+          GladeWidgetAdaptor *prop_adaptor, *adaptor;
+          GParamSpec         *pspec;
 
-  if (priv->translation_domain)
-    glade_xml_node_set_property_string (root, GLADE_TAG_DOMAIN, priv->translation_domain);
-  
-  glade_project_update_comment (project);
-  /* comment_node = glade_xml_node_new_comment (context, project->priv->comment); */
+          /* Unset properties ofcourse dont count... */
+          if (glade_property_original_default (property))
+            continue;
 
-  /* XXX Need to append this to the doc ! not the ROOT !
-     glade_xml_node_append_child (root, comment_node); */
+          /* Check if this property originates from a GTK+ widget class */
+          pspec        = glade_property_class_get_pspec (pclass);
+          prop_adaptor = glade_property_class_get_adaptor (pclass);
+          adaptor      = glade_widget_adaptor_from_pspec (prop_adaptor, pspec);
 
-  glade_project_write_required_libs (project, context, root);
+          catalog = NULL;
+          is_gtk_adaptor = FALSE;
+          g_object_get (adaptor, "catalog", &catalog, NULL);
+          if (strcmp (catalog, "gtk+") == 0)
+            is_gtk_adaptor = TRUE;
+          g_free (catalog);
 
-  glade_project_write_resource_path (project, context, root);
+          /* Check GTK+ property class versions */
+          if (is_gtk_adaptor &&
+              !GPC_VERSION_CHECK (pclass, target_major, target_minor))
+            {
+              target_major = glade_property_class_since_major (pclass);
+              target_minor = glade_property_class_since_minor (pclass);
+            }
+        }
 
-  /* Sort the toplevels */
-  toplevels = g_list_copy (project->priv->tree);
-  toplevels = g_list_sort (toplevels, (GCompareFunc)sort_project_dependancies);
+      /* Check all signal versions here */
+      data.widget = widget;
+      data.major = target_major;
+      data.minor = target_minor;
 
-  for (list = toplevels; list; list = list->next)
-    {
-      GladeWidget *widget;
+      signals = glade_widget_get_signal_list (widget);
+      g_list_foreach (signals, (GFunc)glade_project_introspect_signal_versions, &data);
+      g_list_free (signals);
 
-      widget = glade_widget_get_from_gobject (list->data);
+      if (target_major < data.major)
+        target_major = data.major;
 
-      /* 
-       * Append toplevel widgets. Each widget then takes
-       * care of appending its children.
-       */
-      if (!glade_widget_get_parent (widget))
-        glade_widget_write (widget, context, root);
+      if (target_minor < data.minor)
+        target_minor = data.minor;
     }
 
-  g_list_free (toplevels);
-
-  return context;
+  glade_project_set_target_version (project, "gtk+", target_major,
+                                    target_minor);
 }
 
-/**
- * glade_project_backup:
- * @project: a #GladeProject
- * @path: location to save glade file
- * @error: an error from the G_FILE_ERROR domain.
- *
- * Backup the last file which @project has saved to
- * or was loaded from.
- *
- * If @path is not the same as the current project
- * path, then the current project path will be
- * backed up under the new location.
- *
- * If this the first save, and no persisted file
- * exists, then %TRUE is returned and no backup is made.
- *
- * Returns: %TRUE on success, %FALSE on failure
- */
-gboolean
-glade_project_backup (GladeProject        *project,
-                     const gchar         *path, 
-                     GError             **error)
-{
-  gchar *canonical_path;
-  gchar *destination_path;
-  gchar *content = NULL;
-  gsize  length = 0;
-  gboolean success;
-
-  g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
-
-  if (project->priv->path == NULL)
-    return TRUE;
 
-  canonical_path = glade_util_canonical_path (path);
-  destination_path = g_strconcat (canonical_path, "~", NULL);
-  g_free (canonical_path);
+static gint
+glade_project_count_xml_objects (GladeProject *project,
+                                 GladeXmlNode *root,
+                                 gint count)
+{
+  GladeXmlNode *node;
 
-  success = g_file_get_contents (project->priv->path, &content, &length, error);
-  if (success)
-    success = g_file_set_contents (destination_path, content, length, error);
+  for (node = glade_xml_node_get_children (root);
+       node; node = glade_xml_node_next (node))
+    {
+      if (glade_xml_node_verify_silent (node, GLADE_XML_TAG_WIDGET) ||
+         glade_xml_node_verify_silent (node, GLADE_XML_TAG_TEMPLATE))
+        count = glade_project_count_xml_objects (project, node, ++count);
+      else if (glade_xml_node_verify_silent (node, GLADE_XML_TAG_CHILD))
+        count = glade_project_count_xml_objects (project, node, count);
+    }
+  return count;
+}
 
-  g_free (destination_path);
+void
+glade_project_cancel_load (GladeProject *project)
+{
+  g_return_if_fail (GLADE_IS_PROJECT (project));
 
-  return success;
+  project->priv->load_cancel = TRUE;
 }
 
-/**
- * glade_project_autosave:
- * @project: a #GladeProject
- * @path: location to save glade file
- * @error: an error from the G_FILE_ERROR domain.
- * 
- * Saves an autosave snapshot of @project to it's currently set path
- *
- * If the project was never saved, nothing is done and %TRUE is returned.
- *
- * Returns: %TRUE on success, %FALSE on failure
- */
 gboolean
-glade_project_autosave (GladeProject        *project,
-                       GError             **error)
+glade_project_load_cancelled (GladeProject *project)
 {
-
-  GladeXmlContext *context;
-  GladeXmlDoc *doc;
-  gchar *autosave_path;
-  gint ret;
-
   g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
 
-  if (project->priv->path == NULL)
-    return TRUE;
-
-  autosave_path = glade_project_autosave_name (project->priv->path);
+  return project->priv->load_cancel;
+}
 
-  context = glade_project_write (project);
-  doc = glade_xml_context_get_doc (context);
-  ret = glade_xml_doc_save (doc, autosave_path);
-  glade_xml_context_destroy (context);
+void
+glade_project_push_progress (GladeProject *project)
+{
+  g_return_if_fail (GLADE_IS_PROJECT (project));
 
-  g_free (autosave_path);
+  project->priv->progress_step++;
 
-  return ret > 0;
+  g_signal_emit (project, glade_project_signals[LOAD_PROGRESS], 0,
+                 project->priv->progress_full, project->priv->progress_step);
 }
 
-/**
- * glade_project_save:
- * @project: a #GladeProject
- * @path: location to save glade file
- * @flags: the #GladeVerifyFlags to warn about
- * @error: an error from the %G_FILE_ERROR domain.
- * 
- * Saves @project to the given path. 
- *
- * Returns: %TRUE on success, %FALSE on failure
- */
-gboolean
-glade_project_save_verify (GladeProject        *project,
-                          const gchar         *path,
-                          GladeVerifyFlags     flags,
-                          GError             **error)
-{
-  GladeXmlContext *context;
-  GladeXmlDoc *doc;
-  gchar *canonical_path;
-  gint ret;
-  gchar *autosave_path;
 
-  g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
+/* translators: refers to project name '%s' that targets gtk version '%d.%d' */
+#define PROJECT_TARGET_DIALOG_TITLE_FMT _("%s targets Gtk+ %d.%d")
 
-  if (glade_project_is_loading (project))
-    return FALSE;
+static void
+glade_project_check_target_version (GladeProject *project)
+{
+  GladeProjectPrivate *priv;
+  GHashTable *unknown_classes;
+  gint unknown_objects;
+  gint major, minor;
+  GtkWidget *dialog;
+  GString *text;
+  GList *l;
 
-  if (!glade_project_verify (project, TRUE, flags))
-    return FALSE;
+  glade_project_get_target_version (project, "gtk+", &major, &minor);
+    
+  /* Glade >= 3.10 only targets Gtk 3 */
+  if (major >= 3) return;
 
-  /* Delete any autosaves at this point, if they exist */
-  if (project->priv->path)
+  priv = project->priv;
+  unknown_classes = g_hash_table_new (g_str_hash, g_str_equal);
+  unknown_objects = 0;
+
+  for (l = priv->objects; l; l = g_list_next (l))
     {
-      autosave_path = glade_project_autosave_name (project->priv->path);
-      g_unlink (autosave_path);
-      g_free (autosave_path);
+      if (GLADE_IS_OBJECT_STUB (l->data))
+        {
+          gchar *type;
+          g_object_get (l->data, "object-type", &type, NULL);
+          g_hash_table_insert (unknown_classes, type, NULL);
+          unknown_objects++;
+        }
     }
 
-  /* Save the project */
-  context = glade_project_write (project);
-  doc = glade_xml_context_get_doc (context);
-  ret = glade_xml_doc_save (doc, path);
-  glade_xml_context_destroy (context);
+  if (unknown_objects)
+    {
+      GList *classes = g_hash_table_get_keys (unknown_classes);
 
-  canonical_path = glade_util_canonical_path (path);
-  g_assert (canonical_path);
+      if (unknown_objects == 1)
+        {
+          text = g_string_new (_("Specially because there is an object that can not be build with type "));
+        }
+      else
+        {
+          text = g_string_new ("");
+          g_string_printf (text, _("Specially because there are %d objects that can not be build with types 
"),
+                           unknown_objects);
+        }
 
-  if (project->priv->path == NULL ||
-      strcmp (canonical_path, project->priv->path))
-    {
-      project->priv->path = (g_free (project->priv->path),
-                             g_strdup (canonical_path));
-      g_object_notify_by_pspec (G_OBJECT (project), properties[PROP_PATH]);
+      for (l = classes; l; l = g_list_next (l))
+        {
+          if (g_list_previous (l))
+            g_string_append (text, (g_list_next (l)) ? ", " : _(" and "));
+          
+          g_string_append (text, l->data);
+        }
 
-      glade_project_update_properties_title (project);
+      g_list_free (classes);
     }
+  else 
+    text = NULL;
 
-  glade_project_set_readonly (project,
-                              !glade_util_file_is_writeable (project->priv->
-                                                             path));
-
-  project->priv->mtime = glade_util_get_file_mtime (project->priv->path, NULL);
+  dialog = gtk_message_dialog_new (GTK_WINDOW (glade_app_get_window ()),
+                                   GTK_DIALOG_DESTROY_WITH_PARENT,
+                                   GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
+                                   PROJECT_TARGET_DIALOG_TITLE_FMT,
+                                   glade_project_get_name (project),
+                                   major, minor);
 
-  glade_project_set_modified (project, FALSE);
+  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+                                            _("But this version of Glade is for GTK+ 3 only.\n"
+                                              "Make sure you can run this project with Glade 3.8 with no 
deprecated widgets first.\n"
+                                              "%s"), (text) ? text->str : "");
 
-  if (project->priv->unsaved_number > 0)
-    {
-      glade_id_allocator_release (get_unsaved_number_allocator (),
-                                  project->priv->unsaved_number);
-      project->priv->unsaved_number = 0;
-    }
+  gtk_dialog_run (GTK_DIALOG (dialog));
+  gtk_widget_destroy (dialog);
 
-  g_free (canonical_path);
+  glade_project_set_target_version (project, "gtk+", 3, 0);
 
-  return ret > 0;
+  g_hash_table_destroy (unknown_classes);
+  if (text) g_string_free (text, TRUE);
 }
 
-/**
- * glade_project_save:
- * @project: a #GladeProject
- * @path: location to save glade file
- * @error: an error from the %G_FILE_ERROR domain.
- * 
- * Saves @project to the given path. 
- *
- * Returns: %TRUE on success, %FALSE on failure
- */
-gboolean
-glade_project_save (GladeProject *project, const gchar *path, GError **error)
+static gchar *
+glade_project_autosave_name (const gchar *path)
 {
-  return glade_project_save_verify (project, path,
-                                   GLADE_VERIFY_VERSIONS |
-                                   GLADE_VERIFY_UNRECOGNIZED,
-                                   error);
-}
+  gchar *basename, *dirname, *autoname;
+  gchar *autosave_name;
 
-/**
- * glade_project_preview:
- * @project: a #GladeProject
- * @gwidget: a #GladeWidget
- * 
- * Creates and displays a preview window holding a snapshot of @gwidget's
- * toplevel window in @project. Note that the preview window is only a snapshot
- * of the current state of the project, there is no limit on how many preview
- * snapshots can be taken.
- */
-void
-glade_project_preview (GladeProject *project, GladeWidget *gwidget)
-{
-  GladeXmlContext *context;
-  gchar *text, *pidstr;
-  GladePreview *preview = NULL;
+  basename = g_path_get_basename (path);
+  dirname = g_path_get_dirname (path);
 
-  g_return_if_fail (GLADE_IS_PROJECT (project));
+  autoname = g_strdup_printf ("#%s#", basename);
+  autosave_name = g_build_filename (dirname, autoname, NULL);
 
-  context = glade_project_write (project);
+  g_free (basename);
+  g_free (dirname);
+  g_free (autoname);
 
-  text = glade_xml_dump_from_context (context);
+  return autosave_name;
+}
 
-  gwidget = glade_widget_get_toplevel (gwidget);
-  if (!GTK_IS_WIDGET (glade_widget_get_object (gwidget)))
-    return;
+static gboolean
+glade_project_load_internal (GladeProject *project)
+{
+  GladeProjectPrivate *priv = project->priv;
+  GladeXmlContext *context;
+  GladeXmlDoc *doc;
+  GladeXmlNode *root;
+  GladeXmlNode *node;
+  GladeWidget *widget;
+  gboolean has_gtk_dep = FALSE;
+  gchar *domain;
+  gint count;
+  gchar *autosave_path;
+  time_t mtime, autosave_mtime;
+  gchar *load_path = NULL;
 
-  if ((pidstr = g_object_get_data (G_OBJECT (gwidget), "preview")) != NULL)
-    preview = g_hash_table_lookup (project->priv->previews, pidstr);
+  /* Check if an autosave is more recent then the specified file */
+  autosave_path = glade_project_autosave_name (priv->path);
+  autosave_mtime = glade_util_get_file_mtime (autosave_path, NULL);
+  mtime = glade_util_get_file_mtime (priv->path, NULL);
 
-  if (!preview)
+  if (autosave_mtime > mtime)
     {
-      /* If the previewer program is somehow missing, this can return NULL */
-      preview = glade_preview_launch (gwidget, text);
-      g_return_if_fail (GLADE_IS_PREVIEW (preview));
+      gchar *display_name;
 
-      /* Leave project data on the preview */
-      g_object_set_data (G_OBJECT (preview), "project", project);
+      display_name = glade_project_get_name (project);
 
-      /* Leave preview data on the widget */
-      g_object_set_data_full (G_OBJECT (gwidget),
-                              "preview", 
-                              glade_preview_get_pid_as_str (preview),
-                              g_free);
+      if (glade_util_ui_message (glade_app_get_window (),
+                                GLADE_UI_YES_OR_NO, NULL,
+                                _("An automatically saved version of `%s' is more recent\n\n"
+                                  "Would you like to load the autosave version instead ?"),
+                                display_name))
+       {
+         mtime = autosave_mtime;
+         load_path = g_strdup (autosave_path);
+       }
+      g_free (display_name);
+    }
 
-      g_signal_connect (preview, "exits",
-                        G_CALLBACK (glade_project_preview_exits),
-                        project);
+  g_free (autosave_path);
 
-      /* Add preview to list of previews */
-      g_hash_table_insert (project->priv->previews,
-                           glade_preview_get_pid_as_str (preview),
-                           preview);
-    }
-  else
+  priv->selection = NULL;
+  priv->objects = NULL;
+  priv->loading = TRUE;
+
+  /* get the context & root node of the catalog file */
+  if (!(context =
+        glade_xml_context_new_from_path (load_path ? load_path : priv->path, NULL, NULL)))
     {
-      glade_preview_update (preview, text);
+      g_warning ("Couldn't open glade file [%s].", load_path ? load_path : priv->path);
+      g_free (load_path);
+      priv->loading = FALSE;
+      return FALSE;
     }
 
-  g_free (text);
-}
+  priv->mtime = mtime;
 
-/*******************************************************************
-     Verify code here (versioning, incompatability checks)
- *******************************************************************/
+  doc = glade_xml_context_get_doc (context);
+  root = glade_xml_doc_get_root (doc);
 
-/* Defined here for pretty translator comments (bug in intl tools, for some reason
- * you can only comment about the line directly following, forcing you to write
- * ugly messy code with comments in line breaks inside function calls).
- */
+  if (!glade_xml_node_verify_silent (root, GLADE_XML_TAG_PROJECT))
+    {
+      g_warning ("Couldnt recognize GtkBuilder xml, skipping %s",
+                 load_path ? load_path : priv->path);
+      glade_xml_context_free (context);
+      g_free (load_path);
+      priv->loading = FALSE;
+      return FALSE;
+    }
 
-/* translators: refers to a widget in toolkit version '%s %d.%d' and a project targeting toolkit version '%s 
%d.%d' */
-#define WIDGET_VERSION_CONFLICT_MSGFMT _("This widget was introduced in %s %d.%d " \
-                                         "while project targets %s %d.%d")
+  /* Emit "parse-began" signal */
+  g_signal_emit (project, glade_project_signals[PARSE_BEGAN], 0);
 
-/* translators: refers to a widget '[%s]' introduced in toolkit version '%s %d.%d' */
-#define WIDGET_VERSION_CONFLICT_FMT    _("[%s] Object class '%s' was introduced in %s %d.%d\n")
+  if ((domain = glade_xml_get_property_string (root, GLADE_TAG_DOMAIN)))
+    glade_project_set_translation_domain (project, domain);
 
-#define WIDGET_DEPRECATED_MSG          _("This widget is deprecated")
+  /* XXX Need to load project->priv->comment ! */
+  glade_project_read_comment (project, doc);
 
-/* translators: refers to a widget '[%s]' loaded from toolkit version '%s %d.%d' */
-#define WIDGET_DEPRECATED_FMT          _("[%s] Object class '%s' from %s %d.%d is deprecated\n")
+  /* Read requieres, and do not abort load if there are missing catalog since
+   * GladeObjectStub is created to keep the original xml for unknown object classes
+   */
+  glade_project_read_requires (project, root, load_path ? load_path : priv->path, &has_gtk_dep);
 
+  glade_project_read_resource_path (project, root);
 
-/* translators: refers to a property in toolkit version '%s %d.%d' 
- * and a project targeting toolkit version '%s %d.%d' */
-#define PROP_VERSION_CONFLICT_MSGFMT   _("This property was introduced in %s %d.%d " \
-                                         "while project targets %s %d.%d")
+  /* Launch a dialog if it's going to take enough time to be
+   * worth showing at all */
+  count = glade_project_count_xml_objects (project, root, 0);
+  priv->progress_full = count;
+  priv->progress_step = 0;
 
-/* translators: refers to a property '%s' of widget '[%s]' in toolkit version '%s %d.%d' */
-#define PROP_VERSION_CONFLICT_FMT      _("[%s] Property '%s' of object class '%s' " \
-                                         "was introduced in %s %d.%d\n")
+  for (node = glade_xml_node_get_children (root);
+       node; node = glade_xml_node_next (node))
+    {
+      /* Skip "requires" tags */
+      if (!(glade_xml_node_verify_silent (node, GLADE_XML_TAG_WIDGET) ||
+           glade_xml_node_verify_silent (node, GLADE_XML_TAG_TEMPLATE)))
+        continue;
 
-/* translators: refers to a property '%s' of widget '[%s]' in toolkit version '%s %d.%d' */
-#define PACK_PROP_VERSION_CONFLICT_FMT _("[%s] Packing property '%s' of object class '%s' " \
-                                         "was introduced in %s %d.%d\n")
+      if ((widget = glade_widget_read (project, NULL, node, NULL)) != NULL)
+        glade_project_add_object (project, glade_widget_get_object (widget));
 
-#define PROP_DEPRECATED_MSG            _("This property is deprecated")
+      if (priv->load_cancel)
+        break;
+    }
 
-/* translators: refers to a property '%s' of widget '[%s]' */
-#define PROP_DEPRECATED_FMT            _("[%s] Property '%s' of object class '%s' is deprecated")
+  /* Finished with the xml context */
+  glade_xml_context_free (context);
 
-/* translators: refers to a signal in toolkit version '%s %d.%d' 
- * and a project targeting toolkit version '%s %d.%d' */
-#define SIGNAL_VERSION_CONFLICT_MSGFMT _("This signal was introduced in %s %d.%d " \
-                                         "while project targets %s %d.%d")
+  if (priv->load_cancel)
+    {
+      priv->loading = FALSE;
+      g_free (load_path);
+      return FALSE;
+    }
 
-/* translators: refers to a signal '%s' of widget '[%s]' in toolkit version '%s %d.%d' */
-#define SIGNAL_VERSION_CONFLICT_FMT    _("[%s] Signal '%s' of object class '%s' " \
-                                         "was introduced in %s %d.%d\n")
+  if (!has_gtk_dep)
+    glade_project_introspect_gtk_version (project);
 
-#define SIGNAL_DEPRECATED_MSG          _("This signal is deprecated")
+  if (glade_util_file_is_writeable (priv->path) == FALSE)
+    glade_project_set_readonly (project, TRUE);
 
-/* translators: refers to a signal '%s' of widget '[%s]' */
-#define SIGNAL_DEPRECATED_FMT          _("[%s] Signal '%s' of object class '%s' is deprecated")
+  /* Now we have to loop over all the object properties
+   * and fix'em all ('cause they probably weren't found)
+   */
+  glade_project_fix_object_props (project);
+
+  glade_project_fix_template (project);
+
+  /* Emit "parse-finished" signal */
+  g_signal_emit (project, glade_project_signals[PARSE_FINISHED], 0);
+
+  /* Reset project status here too so that you get a clean
+   * slate after calling glade_project_open().
+   */
+  priv->modified = FALSE;
+  priv->loading = FALSE;
+
+  /* Update ui with versioning info
+   */
+  glade_project_verify_project_for_ui (project);
+
+  glade_project_check_target_version (project);
+  
+  return TRUE;
 
+}
 
 static void
-glade_project_verify_property_internal (GladeProject *project,
-                                        GladeProperty *property,
-                                        const gchar *path_name,
-                                        GString *string,
-                                        gboolean forwidget,
-                                       GladeVerifyFlags flags)
+glade_project_update_properties_title (GladeProject *project)
 {
-  GladeWidgetAdaptor *adaptor, *prop_adaptor;
-  GladePropertyClass *pclass;
-  GParamSpec         *pspec;
-  gint target_major, target_minor;
-  gchar *catalog, *tooltip;
+  gchar *name, *title;
 
-  /* For verification lists, we're only interested in verifying the 'used' state of properties.
-   *
-   * For the UI on the other hand, we want to show warnings on unset properties until they
-   * are set.
-   */
-  if (!forwidget && (glade_property_get_state (property) & GLADE_STATE_CHANGED) == 0)
-    return;
+  /* Update prefs dialogs here... */
+  name = glade_project_get_name (project);
+  title = g_strdup_printf (_("%s document properties"), name);
+  gtk_window_set_title (GTK_WINDOW (project->priv->prefs_dialog), title);
+  g_free (title);
+  g_free (name); 
+}
 
-  pclass       = glade_property_get_class (property);
-  pspec        = glade_property_class_get_pspec (pclass);
-  prop_adaptor = glade_property_class_get_adaptor (pclass);
-  adaptor      = glade_widget_adaptor_from_pspec (prop_adaptor, pspec);
+gboolean
+glade_project_load_from_file (GladeProject *project, const gchar *path)
+{
+  gboolean retval;
 
-  g_object_get (adaptor, "catalog", &catalog, NULL);
-  glade_project_target_version_for_adaptor (project, adaptor,
-                                            &target_major, &target_minor);
+  g_return_val_if_fail (path != NULL, FALSE);
+  g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
 
-  if ((flags & GLADE_VERIFY_VERSIONS) != 0 &&
-      !GPC_VERSION_CHECK (pclass, target_major, target_minor))
-    {
-      if (forwidget)
-        {
-          tooltip = g_strdup_printf (PROP_VERSION_CONFLICT_MSGFMT,
-                                     catalog,
-                                     glade_property_class_since_major (pclass),
-                                     glade_property_class_since_minor (pclass),
-                                     catalog, target_major, target_minor);
+  project->priv->path = glade_util_canonical_path (path);
+  g_object_notify_by_pspec (G_OBJECT (project), glade_project_props[PROP_PATH]);
 
-          glade_property_set_support_warning (property, FALSE, tooltip);
-          g_free (tooltip);
-        }
-      else
-        g_string_append_printf (string,
-                                glade_property_class_get_is_packing (pclass) ?
-                                PACK_PROP_VERSION_CONFLICT_FMT :
-                                  PROP_VERSION_CONFLICT_FMT,
-                                  path_name,
-                                  glade_property_class_get_name (pclass),
-                                  glade_widget_adaptor_get_title (adaptor),
-                                  catalog,
-                                  glade_property_class_since_major (pclass),
-                                  glade_property_class_since_minor (pclass));
+  if ((retval = glade_project_load_internal (project)))
+    glade_project_update_properties_title (project);
+
+  return retval;
+}
+
+/**
+ * glade_project_load:
+ * @path:
+ * 
+ * Opens a project at the given path.
+ *
+ * Returns: a new #GladeProject for the opened project on success, %NULL on 
+ *          failure
+ */
+GladeProject *
+glade_project_load (const gchar *path)
+{
+  GladeProject *project;
+
+  g_return_val_if_fail (path != NULL, NULL);
+
+  project = g_object_new (GLADE_TYPE_PROJECT, NULL);
+
+  project->priv->path = glade_util_canonical_path (path);
+
+  if (glade_project_load_internal (project))
+    {
+      glade_project_update_properties_title (project);
+      return project;
     }
-  else if ((flags & GLADE_VERIFY_DEPRECATIONS) != 0 &&
-          glade_property_class_deprecated (pclass))
+  else
     {
-      if (forwidget)
-       glade_property_set_support_warning (property, FALSE, PROP_DEPRECATED_MSG);
-      else
-        g_string_append_printf (string,
-                                PROP_DEPRECATED_FMT,
-                                path_name,
-                               glade_property_class_get_name (pclass),
-                                glade_widget_adaptor_get_title (adaptor));
+      g_object_unref (project);
+      return NULL;
     }
-  else if (forwidget)
-    glade_property_set_support_warning (property, FALSE, NULL);
+}
 
-  g_free (catalog);
+/*******************************************************************
+                    Writing project code here
+ *******************************************************************/
+
+#define GLADE_XML_COMMENT "Generated with "PACKAGE_NAME
+
+static gchar *
+glade_project_make_comment (void)
+{
+  time_t now = time (NULL);
+  gchar *comment;
+  comment = g_strdup_printf (GLADE_XML_COMMENT " " PACKAGE_VERSION " on %s",
+                             ctime (&now));
+  glade_util_replace (comment, '\n', ' ');
+
+  return comment;
 }
 
 static void
-glade_project_verify_properties_internal (GladeWidget *widget,
-                                          const gchar *path_name,
-                                          GString *string,
-                                          gboolean forwidget,
-                                         GladeVerifyFlags flags)
+glade_project_update_comment (GladeProject *project)
 {
-  GList *list;
-  GladeProperty *property;
+  gchar **lines, **l, *comment = NULL;
 
-  for (list = glade_widget_get_properties (widget); list; list = list->next)
+  /* If project has no comment -> add the new one */
+  if (project->priv->comment == NULL)
     {
-      property = list->data;
-      glade_project_verify_property_internal (glade_widget_get_project (widget), 
-                                              property, path_name,
-                                              string, forwidget, flags);
+      project->priv->comment = glade_project_make_comment ();
+      return;
     }
 
-  /* Sometimes widgets on the clipboard have packing props with no parent */
-  if (glade_widget_get_parent (widget))
+  for (lines = l = g_strsplit (project->priv->comment, "\n", 0); *l; l++)
     {
-      for (list = glade_widget_get_packing_properties (widget); list; list = list->next)
+      gchar *start;
+
+      /* Ignore leading spaces */
+      for (start = *l; *start && g_ascii_isspace (*start); start++);
+
+      if (g_str_has_prefix (start, GLADE_XML_COMMENT))
         {
-          property = list->data;
-          glade_project_verify_property_internal (glade_widget_get_project (widget), 
-                                                  property, path_name, string, forwidget, flags);
+          /* This line was generated by glade -> updating... */
+          g_free (*l);
+          *l = comment = glade_project_make_comment ();
         }
     }
+
+  if (comment)
+    {
+      g_free (project->priv->comment);
+      project->priv->comment = g_strjoinv ("\n", lines);
+    }
+
+  g_strfreev (lines);
 }
 
 static void
-glade_project_verify_signal_internal (GladeWidget *widget,
-                                      GladeSignal *signal,
-                                      const gchar *path_name,
-                                      GString *string,
-                                      gboolean forwidget,
-                                     GladeVerifyFlags flags)
+glade_project_write_required_libs (GladeProject *project,
+                                   GladeXmlContext *context,
+                                   GladeXmlNode *root)
 {
-  GladeSignalClass   *signal_class;
-  GladeWidgetAdaptor *adaptor;
-  gint                target_major, target_minor;
-  gchar              *catalog;
-
-  signal_class =
-      glade_widget_adaptor_get_signal_class (glade_widget_get_adaptor (widget),
-                                             glade_signal_get_name (signal));
-
-  if (!signal_class)
-    return;
-
-  adaptor = glade_signal_class_get_adaptor (signal_class);
-
-  g_object_get (adaptor, "catalog", &catalog, NULL);
-  glade_project_target_version_for_adaptor (glade_widget_get_project (widget),
-                                            adaptor,
-                                            &target_major, &target_minor);
+  GladeXmlNode *req_node;
+  GList *required, *list;
+  gint major, minor;
+  gchar *version;
 
-  if ((flags & GLADE_VERIFY_VERSIONS) != 0 &&
-      !GSC_VERSION_CHECK (signal_class, target_major, target_minor))
+  if ((required = glade_project_required_libs (project)) != NULL)
     {
-      if (forwidget)
+      for (list = required; list; list = list->next)
         {
-          gchar *warning;
+          glade_project_get_target_version (project, (gchar *) list->data,
+                                            &major, &minor);
 
-          warning = g_strdup_printf (SIGNAL_VERSION_CONFLICT_MSGFMT,
-                                     catalog,
-                                     glade_signal_class_since_major (signal_class),
-                                     glade_signal_class_since_minor (signal_class),
-                                     catalog, target_major, target_minor);
-          glade_signal_set_support_warning (signal, warning);
-          g_free (warning);
-        }
-      else
-        g_string_append_printf (string,
-                                SIGNAL_VERSION_CONFLICT_FMT,
-                                path_name,
-                                glade_signal_get_name (signal),
-                                glade_widget_adaptor_get_title (adaptor),
-                                catalog,
-                                glade_signal_class_since_major (signal_class),
-                                glade_signal_class_since_minor (signal_class));
-    }
-  else if ((flags & GLADE_VERIFY_DEPRECATIONS) != 0 &&
-          glade_signal_class_deprecated (signal_class))
-    {
-      if (forwidget)
-       glade_signal_set_support_warning (signal, SIGNAL_DEPRECATED_MSG);
-      else
-        g_string_append_printf (string,
-                                SIGNAL_DEPRECATED_FMT,
-                                path_name,
-                                glade_signal_get_name (signal),
-                                glade_widget_adaptor_get_title (adaptor));
-    }
-  else if (forwidget)
-    glade_signal_set_support_warning (signal, NULL);
-
-  g_free (catalog);
-}
-
-void
-glade_project_verify_property (GladeProperty *property)
-{
-  GladeWidget  *widget;
-  GladeProject *project;
-
-  g_return_if_fail (GLADE_IS_PROPERTY (property));
+          version = g_strdup_printf ("%d.%d", major, minor);
 
-  widget  = glade_property_get_widget (property);
-  project = glade_widget_get_project (widget);
+          /* Write the standard requires tag */
+          if (GLADE_GTKBUILDER_HAS_VERSIONING (major, minor))
+            {
+              req_node = glade_xml_node_new (context, GLADE_XML_TAG_REQUIRES);
+              glade_xml_node_append_child (root, req_node);
+              glade_xml_node_set_property_string (req_node,
+                                                  GLADE_XML_TAG_LIB,
+                                                  (gchar *) list->data);
+            }
+          else
+            {
+              gchar *comment = g_strdup_printf (" interface-requires %s %s ",
+                                                (gchar *) list->data, version);
+              req_node = glade_xml_node_new_comment (context, comment);
+              glade_xml_node_append_child (root, req_node);
+              g_free (comment);
+            }
 
-  if (project)
-    glade_project_verify_property_internal (project, property, NULL, NULL, TRUE,
-                                           GLADE_VERIFY_VERSIONS     |
-                                           GLADE_VERIFY_DEPRECATIONS |
-                                           GLADE_VERIFY_UNRECOGNIZED);
-}
+          glade_xml_node_set_property_string (req_node, GLADE_XML_TAG_VERSION,
+                                              version);
+          g_free (version);
 
-void
-glade_project_verify_signal (GladeWidget *widget, GladeSignal *signal)
-{
-  glade_project_verify_signal_internal (widget, signal, NULL, NULL, TRUE,
-                                       GLADE_VERIFY_VERSIONS     |
-                                       GLADE_VERIFY_DEPRECATIONS |
-                                       GLADE_VERIFY_UNRECOGNIZED);
+        }
+      g_list_foreach (required, (GFunc) g_free, NULL);
+      g_list_free (required);
+    }
 }
 
 static void
-glade_project_verify_signals (GladeWidget *widget,
-                              const gchar *path_name,
-                              GString *string,
-                              gboolean forwidget,
-                             GladeVerifyFlags flags)
+glade_project_write_resource_path (GladeProject *project,
+                                   GladeXmlContext *context,
+                                   GladeXmlNode *root)
 {
-  GladeSignal *signal;
-  GList *signals, *list;
-
-  if ((signals = glade_widget_get_signal_list (widget)) != NULL)
+  GladeXmlNode *path_node;
+  if (project->priv->resource_path)
     {
-      for (list = signals; list; list = list->next)
-        {
-          signal = list->data;
-          glade_project_verify_signal_internal (widget, signal, path_name,
-                                                string, forwidget, flags);
-        }
-      g_list_free (signals);
+      gchar *comment = g_strdup_printf (" interface-local-resource-path %s ",
+                                        project->priv->resource_path);
+      path_node = glade_xml_node_new_comment (context, comment);
+      glade_xml_node_append_child (root, path_node);
+      g_free (comment);
     }
 }
 
-
-/**
- * glade_project_verify_properties:
- * @widget: A #GladeWidget
- *
- * Synchonizes @widget with user visible information
- * about version compatability and notifies the UI
- * it should update.
- */
-static void
-glade_project_verify_properties (GladeWidget *widget)
+static gint
+sort_project_dependancies (GObject *a, GObject *b)
 {
-  GladeProject *project;
-
-  g_return_if_fail (GLADE_IS_WIDGET (widget));
-
-  project = glade_widget_get_project (widget);
-  if (!project || project->priv->loading)
-    return;
+  GladeWidget *ga, *gb;
 
-  glade_project_verify_properties_internal (widget, NULL, NULL, TRUE,
-                                           GLADE_VERIFY_VERSIONS     |
-                                           GLADE_VERIFY_DEPRECATIONS |
-                                           GLADE_VERIFY_UNRECOGNIZED);
-  glade_project_verify_signals (widget, NULL, NULL, TRUE,
-                               GLADE_VERIFY_VERSIONS     |
-                               GLADE_VERIFY_DEPRECATIONS |
-                               GLADE_VERIFY_UNRECOGNIZED);
+  ga = glade_widget_get_from_gobject (a);
+  gb = glade_widget_get_from_gobject (b);
 
-  glade_widget_support_changed (widget);
+  if (glade_widget_depends (ga, gb))
+    return 1;
+  else if (glade_widget_depends (gb, ga))
+    return -1;
+  else
+    return strcmp (glade_widget_get_name (ga), glade_widget_get_name (gb));
 }
 
-static gboolean
-glade_project_verify_dialog (GladeProject *project,
-                             GString *string,
-                            gboolean saving)
+static GladeXmlContext *
+glade_project_write (GladeProject *project)
 {
-  GtkWidget *swindow;
-  GtkWidget *textview;
-  GtkWidget *expander;
-  GtkTextBuffer *buffer;
-  gchar *name;
-  gboolean ret;
-
-  swindow = gtk_scrolled_window_new (NULL, NULL);
-  textview = gtk_text_view_new ();
-  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
-  expander = gtk_expander_new (_("Details"));
+  GladeProjectPrivate *priv = project->priv;
+  GladeXmlContext *context;
+  GladeXmlDoc *doc;
+  GladeXmlNode *root;           /* *comment_node; */
+  GList *list;
+  GList *toplevels;
 
-  gtk_text_buffer_set_text (buffer, string->str, -1);
+  doc = glade_xml_doc_new ();
+  context = glade_xml_context_new (doc, NULL);
+  root = glade_xml_node_new (context, GLADE_XML_TAG_PROJECT);
+  glade_xml_doc_set_root (doc, root);
 
-  gtk_container_add (GTK_CONTAINER (swindow), textview);
-  gtk_container_add (GTK_CONTAINER (expander), swindow);
-  gtk_widget_show_all (expander);
+  if (priv->translation_domain)
+    glade_xml_node_set_property_string (root, GLADE_TAG_DOMAIN, priv->translation_domain);
+  
+  glade_project_update_comment (project);
+  /* comment_node = glade_xml_node_new_comment (context, project->priv->comment); */
 
-  gtk_widget_set_size_request (swindow, 800, -1);
+  /* XXX Need to append this to the doc ! not the ROOT !
+     glade_xml_node_append_child (root, comment_node); */
 
-  name = glade_project_get_name (project);
-  ret = glade_util_ui_message (glade_app_get_window (),
-                               saving ? GLADE_UI_YES_OR_NO : GLADE_UI_INFO,
-                               expander,
-                               saving ?
-                               _("Project \"%s\" has errors. Save anyway?") :
-                               _("Project \"%s\" has deprecated widgets "
-                                 "and/or version mismatches."), name);
-  g_free (name);
+  glade_project_write_required_libs (project, context, root);
 
-  return ret;
-}
+  glade_project_write_resource_path (project, context, root);
 
+  /* Sort the toplevels */
+  toplevels = g_list_copy (project->priv->tree);
+  toplevels = g_list_sort (toplevels, (GCompareFunc)sort_project_dependancies);
 
-static gboolean
-glade_project_verify (GladeProject *project, gboolean saving, GladeVerifyFlags flags)
-{
-  GString *string = g_string_new (NULL);
-  GList *list;
-  gboolean ret = TRUE;
-  
-  for (list = project->priv->objects; list; list = list->next)
+  for (list = toplevels; list; list = list->next)
     {
-      GladeWidget *widget = glade_widget_get_from_gobject (list->data);
-      
-      if ((flags & GLADE_VERIFY_UNRECOGNIZED) != 0 &&
-         GLADE_IS_OBJECT_STUB (list->data))
-        {
-          gchar *type;
-          g_object_get (list->data, "object-type", &type, NULL);
-          
-          g_string_append_printf (string, _("Object %s has unrecognized type %s\n"), 
-                                  glade_widget_get_name (widget), type);
-          g_free (type);
-        }
-      else
-        {
-          gchar *path_name = glade_widget_generate_path_name (widget);
-
-          glade_project_verify_adaptor (project, glade_widget_get_adaptor (widget),
-                                        path_name, string, flags, FALSE, NULL);
-          glade_project_verify_properties_internal (widget, path_name, string, FALSE, flags);
-          glade_project_verify_signals (widget, path_name, string, FALSE, flags);
-
-          g_free (path_name);
-        }
-    }
+      GladeWidget *widget;
 
-  if (string->len > 0)
-    {
-      ret = glade_project_verify_dialog (project, string, saving);
+      widget = glade_widget_get_from_gobject (list->data);
 
-      if (!saving)
-        ret = FALSE;
+      /* 
+       * Append toplevel widgets. Each widget then takes
+       * care of appending its children.
+       */
+      if (!glade_widget_get_parent (widget))
+        glade_widget_write (widget, context, root);
     }
 
-  g_string_free (string, TRUE);
-
-  return ret;
-}
-
-static void
-glade_project_target_version_for_adaptor (GladeProject *project,
-                                          GladeWidgetAdaptor *adaptor,
-                                          gint *major,
-                                          gint *minor)
-{
-  gchar *catalog = NULL;
-
-  g_object_get (adaptor, "catalog", &catalog, NULL);
-  glade_project_get_target_version (project, catalog, major, minor);
-  g_free (catalog);
-}
-
-static void
-glade_project_verify_adaptor (GladeProject *project,
-                              GladeWidgetAdaptor *adaptor,
-                              const gchar *path_name,
-                              GString *string,
-                              GladeVerifyFlags flags,
-                              gboolean forwidget,
-                              GladeSupportMask *mask)
-{
-  GladeSupportMask support_mask = GLADE_SUPPORT_OK;
-  GladeWidgetAdaptor *adaptor_iter;
-  gint target_major, target_minor;
-  gchar *catalog = NULL;
-
-  for (adaptor_iter = adaptor; adaptor_iter && support_mask == GLADE_SUPPORT_OK;
-       adaptor_iter = glade_widget_adaptor_get_parent_adaptor (adaptor_iter))
-    {
-
-      g_object_get (adaptor_iter, "catalog", &catalog, NULL);
-      glade_project_target_version_for_adaptor (project, adaptor_iter,
-                                                &target_major, &target_minor);
-
-      /* Only one versioning message (builder or otherwise)...
-       */
-      if ((flags & GLADE_VERIFY_VERSIONS) != 0 &&
-         !GWA_VERSION_CHECK (adaptor_iter, target_major, target_minor))
-        {
-          if (forwidget)
-            g_string_append_printf (string,
-                                    WIDGET_VERSION_CONFLICT_MSGFMT,
-                                    catalog,
-                                    GWA_VERSION_SINCE_MAJOR (adaptor_iter),
-                                    GWA_VERSION_SINCE_MINOR (adaptor_iter),
-                                    catalog, target_major, target_minor);
-          else
-            g_string_append_printf (string,
-                                    WIDGET_VERSION_CONFLICT_FMT,
-                                    path_name, 
-                                    glade_widget_adaptor_get_title (adaptor_iter),
-                                    catalog,
-                                    GWA_VERSION_SINCE_MAJOR (adaptor_iter),
-                                    GWA_VERSION_SINCE_MINOR (adaptor_iter));
-
-          support_mask |= GLADE_SUPPORT_MISMATCH;
-        }
-
-      if ((flags & GLADE_VERIFY_DEPRECATIONS) != 0 &&
-         GWA_DEPRECATED (adaptor_iter))
-        {
-          if (forwidget)
-            {
-              if (string->len)
-                g_string_append (string, "\n");
-
-              g_string_append_printf (string, WIDGET_DEPRECATED_MSG);
-            }
-          else
-            g_string_append_printf (string, WIDGET_DEPRECATED_FMT,
-                                    path_name, 
-                                    glade_widget_adaptor_get_title (adaptor_iter), 
-                                    catalog, target_major, target_minor);
-
-          support_mask |= GLADE_SUPPORT_DEPRECATED;
-        }
-      g_free (catalog);
-    }
-  if (mask)
-    *mask = support_mask;
+  g_list_free (toplevels);
 
+  return context;
 }
 
 /**
- * glade_project_verify_widget_adaptor:
- * @project: A #GladeProject
- * @adaptor: the #GladeWidgetAdaptor to verify
- * @mask: a return location for a #GladeSupportMask
- * 
- * Checks the supported state of this widget adaptor
- * and generates a string to show in the UI describing why.
+ * glade_project_backup:
+ * @project: a #GladeProject
+ * @path: location to save glade file
+ * @error: an error from the G_FILE_ERROR domain.
  *
- * Returns: A newly allocated string 
+ * Backup the last file which @project has saved to
+ * or was loaded from.
+ *
+ * If @path is not the same as the current project
+ * path, then the current project path will be
+ * backed up under the new location.
+ *
+ * If this the first save, and no persisted file
+ * exists, then %TRUE is returned and no backup is made.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
  */
-gchar *
-glade_project_verify_widget_adaptor (GladeProject *project,
-                                     GladeWidgetAdaptor *adaptor,
-                                     GladeSupportMask *mask)
+gboolean
+glade_project_backup (GladeProject        *project,
+                     const gchar         *path, 
+                     GError             **error)
 {
-  GString *string = g_string_new (NULL);
-  gchar *ret = NULL;
-
-  glade_project_verify_adaptor (project, adaptor, NULL,
-                                string,
-                               GLADE_VERIFY_VERSIONS     |
-                               GLADE_VERIFY_DEPRECATIONS |
-                               GLADE_VERIFY_UNRECOGNIZED,
-                               TRUE, mask);
-
-  /* there was a '\0' byte... */
-  if (string->len > 0)
-    {
-      ret = string->str;
-      g_string_free (string, FALSE);
-    }
-  else
-    g_string_free (string, TRUE);
-
+  gchar *canonical_path;
+  gchar *destination_path;
+  gchar *content = NULL;
+  gsize  length = 0;
+  gboolean success;
 
-  return ret;
-}
+  g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
 
+  if (project->priv->path == NULL)
+    return TRUE;
 
-/**
- * glade_project_verify_project_for_ui:
- * @project: A #GladeProject
- * 
- * Checks the project and updates warning strings in the UI
- */
-static void
-glade_project_verify_project_for_ui (GladeProject *project)
-{
-  GList *list;
-  GladeWidget *widget;
+  canonical_path = glade_util_canonical_path (path);
+  destination_path = g_strconcat (canonical_path, "~", NULL);
+  g_free (canonical_path);
 
-  /* Sync displayable info here */
-  for (list = project->priv->objects; list; list = list->next)
-    {
-      widget = glade_widget_get_from_gobject (list->data);
+  success = g_file_get_contents (project->priv->path, &content, &length, error);
+  if (success)
+    success = g_file_set_contents (destination_path, content, length, error);
 
-      /* Update the support warnings for widget's properties */
-      glade_project_verify_properties (widget);
+  g_free (destination_path);
 
-      /* Update the support warning for widget */
-      glade_widget_verify (widget);
-    }
+  return success;
 }
 
 /**
- * glade_project_get_widget_by_name:
+ * glade_project_autosave:
  * @project: a #GladeProject
- * @ancestor: The toplevel project object to search under
- * @name: The user visible name of the widget we are looking for
- * 
- * Searches under @ancestor in @project looking for a #GladeWidget named @name.
+ * @path: location to save glade file
+ * @error: an error from the G_FILE_ERROR domain.
  * 
- * Returns: a pointer to the widget, %NULL if the widget does not exist
+ * Saves an autosave snapshot of @project to it's currently set path
+ *
+ * If the project was never saved, nothing is done and %TRUE is returned.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
  */
-GladeWidget *
-glade_project_get_widget_by_name (GladeProject *project,
-                                  const gchar  *name)
+gboolean
+glade_project_autosave (GladeProject        *project,
+                       GError             **error)
 {
-  GList *list;
 
-  g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
-  g_return_val_if_fail (name != NULL, NULL);
+  GladeXmlContext *context;
+  GladeXmlDoc *doc;
+  gchar *autosave_path;
+  gint ret;
 
-  for (list = project->priv->objects; list; list = list->next)
-    {
-      GladeWidget *widget;
+  g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
 
-      widget = glade_widget_get_from_gobject (list->data);
+  if (project->priv->path == NULL)
+    return TRUE;
 
-      if (strcmp (glade_widget_get_name (widget), name) == 0)
-        return widget;
-    }
+  autosave_path = glade_project_autosave_name (project->priv->path);
 
-  return NULL;
-}
+  context = glade_project_write (project);
+  doc = glade_xml_context_get_doc (context);
+  ret = glade_xml_doc_save (doc, autosave_path);
+  glade_xml_context_destroy (context);
 
-static void
-glade_project_release_widget_name (GladeProject *project,
-                                   GladeWidget *gwidget,
-                                   const char *widget_name)
-{
-  glade_name_context_release_name (project->priv->widget_names, widget_name);
+  g_free (autosave_path);
+
+  return ret > 0;
 }
 
 /**
- * glade_project_available_widget_name:
+ * glade_project_save:
  * @project: a #GladeProject
- * @widget: the #GladeWidget intended to recieve a new name
- * @name: base name of the widget to create
- *
- * Checks whether @name is an appropriate name for @widget.
+ * @path: location to save glade file
+ * @flags: the #GladeVerifyFlags to warn about
+ * @error: an error from the %G_FILE_ERROR domain.
+ * 
+ * Saves @project to the given path. 
  *
- * Returns: whether the name is available or not.
+ * Returns: %TRUE on success, %FALSE on failure
  */
 gboolean
-glade_project_available_widget_name (GladeProject *project,
-                                     GladeWidget *widget,
-                                     const gchar *name)
+glade_project_save_verify (GladeProject        *project,
+                          const gchar         *path,
+                          GladeVerifyFlags     flags,
+                          GError             **error)
 {
+  GladeXmlContext *context;
+  GladeXmlDoc *doc;
+  gchar *canonical_path;
+  gint ret;
+  gchar *autosave_path;
+
   g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
-  g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
 
-  if (!name || !name[0])
+  if (glade_project_is_loading (project))
     return FALSE;
 
-  return !glade_name_context_has_name (project->priv->widget_names, name);
-}
+  if (!glade_project_verify (project, TRUE, flags))
+    return FALSE;
 
-static void
-glade_project_reserve_widget_name (GladeProject *project,
-                                   GladeWidget *gwidget,
-                                   const char *widget_name)
-{
-  if (!glade_project_available_widget_name (project, gwidget, widget_name))
+  /* Delete any autosaves at this point, if they exist */
+  if (project->priv->path)
     {
-      g_warning ("BUG: widget '%s' attempting to reserve an unavailable widget name '%s' !",
-                 glade_widget_get_name (gwidget), widget_name);
-      return;
+      autosave_path = glade_project_autosave_name (project->priv->path);
+      g_unlink (autosave_path);
+      g_free (autosave_path);
     }
 
-  /* Add to name context */
-  glade_name_context_add_name (project->priv->widget_names, widget_name);
+  /* Save the project */
+  context = glade_project_write (project);
+  doc = glade_xml_context_get_doc (context);
+  ret = glade_xml_doc_save (doc, path);
+  glade_xml_context_destroy (context);
+
+  canonical_path = glade_util_canonical_path (path);
+  g_assert (canonical_path);
+
+  if (project->priv->path == NULL ||
+      strcmp (canonical_path, project->priv->path))
+    {
+      project->priv->path = (g_free (project->priv->path),
+                             g_strdup (canonical_path));
+      g_object_notify_by_pspec (G_OBJECT (project), glade_project_props[PROP_PATH]);
+
+      glade_project_update_properties_title (project);
+    }
+
+  glade_project_set_readonly (project,
+                              !glade_util_file_is_writeable (project->priv->
+                                                             path));
+
+  project->priv->mtime = glade_util_get_file_mtime (project->priv->path, NULL);
+
+  glade_project_set_modified (project, FALSE);
+
+  if (project->priv->unsaved_number > 0)
+    {
+      glade_id_allocator_release (get_unsaved_number_allocator (),
+                                  project->priv->unsaved_number);
+      project->priv->unsaved_number = 0;
+    }
+
+  g_free (canonical_path);
+
+  return ret > 0;
 }
 
 /**
- * glade_project_new_widget_name:
+ * glade_project_save:
  * @project: a #GladeProject
- * @widget: the #GladeWidget intended to recieve a new name
- * @base_name: base name of the widget to create
- *
- * Creates a new name for a widget that doesn't collide with any of the names 
- * already in @project. This name will start with @base_name.
+ * @path: location to save glade file
+ * @error: an error from the %G_FILE_ERROR domain.
+ * 
+ * Saves @project to the given path. 
  *
- * Returns: a string containing the new name, %NULL if there is not enough 
- *          memory for this string
+ * Returns: %TRUE on success, %FALSE on failure
  */
-gchar *
-glade_project_new_widget_name (GladeProject *project,
-                               GladeWidget *widget,
-                               const gchar *base_name)
+gboolean
+glade_project_save (GladeProject *project, const gchar *path, GError **error)
 {
-  gchar *name;
-
-  g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
-  g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
-  g_return_val_if_fail (base_name && base_name[0], NULL);
-
-  name = glade_name_context_new_name (project->priv->widget_names, base_name);
-
-  return name;
+  return glade_project_save_verify (project, path,
+                                   GLADE_VERIFY_VERSIONS |
+                                   GLADE_VERIFY_UNRECOGNIZED,
+                                   error);
 }
 
 /**
- * glade_project_set_widget_name:
+ * glade_project_preview:
  * @project: a #GladeProject
- * @widget: the #GladeWidget to set a name on
- * @name: the name to set.
- *
- * Sets @name on @widget in @project, if @name is not
- * available then a new name will be used.
+ * @gwidget: a #GladeWidget
+ * 
+ * Creates and displays a preview window holding a snapshot of @gwidget's
+ * toplevel window in @project. Note that the preview window is only a snapshot
+ * of the current state of the project, there is no limit on how many preview
+ * snapshots can be taken.
  */
 void
-glade_project_set_widget_name (GladeProject *project,
-                               GladeWidget *widget,
-                               const gchar *name)
+glade_project_preview (GladeProject *project, GladeWidget *gwidget)
 {
-  gchar *new_name;
-  GtkTreeIter iter;
-  GtkTreePath *path;
+  GladeXmlContext *context;
+  gchar *text, *pidstr;
+  GladePreview *preview = NULL;
 
   g_return_if_fail (GLADE_IS_PROJECT (project));
-  g_return_if_fail (GLADE_IS_WIDGET (widget));
-  g_return_if_fail (name && name[0]);
 
-  if (strcmp (name, glade_widget_get_name (widget)) == 0)
-    return;
+  context = glade_project_write (project);
 
-  /* Police the widget name */
-  if (!glade_project_available_widget_name (project, widget, name))
-    new_name = glade_project_new_widget_name (project, widget, name);
-  else
-    new_name = g_strdup (name);
+  text = glade_xml_dump_from_context (context);
 
-  glade_project_reserve_widget_name (project, widget, new_name);
+  gwidget = glade_widget_get_toplevel (gwidget);
+  if (!GTK_IS_WIDGET (glade_widget_get_object (gwidget)))
+    return;
 
-  /* Release old name and set new widget name */
-  glade_project_release_widget_name (project, widget, glade_widget_get_name (widget));
-  glade_widget_set_name (widget, new_name);
+  if ((pidstr = g_object_get_data (G_OBJECT (gwidget), "preview")) != NULL)
+    preview = g_hash_table_lookup (project->priv->previews, pidstr);
 
-  g_signal_emit (G_OBJECT (project),
-                 glade_project_signals[WIDGET_NAME_CHANGED], 0, widget);
+  if (!preview)
+    {
+      /* If the previewer program is somehow missing, this can return NULL */
+      preview = glade_preview_launch (gwidget, text);
+      g_return_if_fail (GLADE_IS_PREVIEW (preview));
 
-  g_free (new_name);
+      /* Leave project data on the preview */
+      g_object_set_data (G_OBJECT (preview), "project", project);
 
-  /* Notify views about the iter change */
-  glade_project_model_get_iter_for_object (project, glade_widget_get_object (widget), &iter);
-  path = gtk_tree_model_get_path (GTK_TREE_MODEL (project), &iter);
-  gtk_tree_model_row_changed (GTK_TREE_MODEL (project), path, &iter);
-  gtk_tree_path_free (path);
-}
+      /* Leave preview data on the widget */
+      g_object_set_data_full (G_OBJECT (gwidget),
+                              "preview", 
+                              glade_preview_get_pid_as_str (preview),
+                              g_free);
 
-static void
-glade_project_notify_row_has_child (GladeProject *project,
-                                   GladeWidget  *gwidget,
-                                   gboolean      adding)
-{
-  GladeWidget *parent;
-  gint         siblings;
-       
-  parent = glade_widget_get_parent (gwidget);
+      g_signal_connect (preview, "exits",
+                        G_CALLBACK (glade_project_preview_exits),
+                        project);
 
-  if (parent)
+      /* Add preview to list of previews */
+      g_hash_table_insert (project->priv->previews,
+                           glade_preview_get_pid_as_str (preview),
+                           preview);
+    }
+  else
     {
-      siblings = glade_project_count_children (project, parent);
-
-      if (siblings == (adding ? 1 : 0))
-       {
-         GtkTreePath *path;
-         GtkTreeIter  iter;
-
-         glade_project_model_get_iter_for_object (project, 
-                                                  glade_widget_get_object (parent), &iter);
-         path = gtk_tree_model_get_path (GTK_TREE_MODEL (project), &iter);
-         gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (project), path, &iter);
-         gtk_tree_path_free (path);
-       }
+      glade_preview_update (preview, text);
     }
+
+  g_free (text);
 }
 
-static void
-glade_project_notify_row_inserted (GladeProject *project, GladeWidget *gwidget)
-{
-  GtkTreeIter iter;
-  GtkTreePath *path;
+/*******************************************************************
+     Verify code here (versioning, incompatability checks)
+ *******************************************************************/
 
-  /* The state of old iters go invalid and then the new iter is valid
-   * until the next change */
-  project->priv->stamp++;
+/* Defined here for pretty translator comments (bug in intl tools, for some reason
+ * you can only comment about the line directly following, forcing you to write
+ * ugly messy code with comments in line breaks inside function calls).
+ */
 
-  glade_project_model_get_iter_for_object (project, glade_widget_get_object (gwidget), &iter);
-  path = gtk_tree_model_get_path (GTK_TREE_MODEL (project), &iter);
-  gtk_tree_model_row_inserted (GTK_TREE_MODEL (project), path, &iter);
-  gtk_tree_path_free (path);
+/* translators: refers to a widget in toolkit version '%s %d.%d' and a project targeting toolkit version '%s 
%d.%d' */
+#define WIDGET_VERSION_CONFLICT_MSGFMT _("This widget was introduced in %s %d.%d " \
+                                         "while project targets %s %d.%d")
 
-  glade_project_notify_row_has_child (project, gwidget, TRUE);
-}
+/* translators: refers to a widget '[%s]' introduced in toolkit version '%s %d.%d' */
+#define WIDGET_VERSION_CONFLICT_FMT    _("[%s] Object class '%s' was introduced in %s %d.%d\n")
 
-static void
-glade_project_notify_row_deleted (GladeProject *project, GladeWidget *gwidget)
-{
-  GtkTreeIter iter;
-  GtkTreePath *path;
+#define WIDGET_DEPRECATED_MSG          _("This widget is deprecated")
 
-  glade_project_model_get_iter_for_object (project, glade_widget_get_object (gwidget), &iter);
-  path = gtk_tree_model_get_path (GTK_TREE_MODEL (project), &iter);
+/* translators: refers to a widget '[%s]' loaded from toolkit version '%s %d.%d' */
+#define WIDGET_DEPRECATED_FMT          _("[%s] Object class '%s' from %s %d.%d is deprecated\n")
 
-  gtk_tree_model_row_deleted (GTK_TREE_MODEL (project), path);
-  gtk_tree_path_free (path);
 
-  project->priv->stamp++;
-}
+/* translators: refers to a property in toolkit version '%s %d.%d' 
+ * and a project targeting toolkit version '%s %d.%d' */
+#define PROP_VERSION_CONFLICT_MSGFMT   _("This property was introduced in %s %d.%d " \
+                                         "while project targets %s %d.%d")
 
-void
-glade_project_check_reordered (GladeProject *project,
-                               GladeWidget  *parent,
-                               GList        *old_order)
-{
-  GList       *new_order, *l, *ll;
+/* translators: refers to a property '%s' of widget '[%s]' in toolkit version '%s %d.%d' */
+#define PROP_VERSION_CONFLICT_FMT      _("[%s] Property '%s' of object class '%s' " \
+                                         "was introduced in %s %d.%d\n")
 
-  g_return_if_fail (GLADE_IS_PROJECT (project));
-  g_return_if_fail (GLADE_IS_WIDGET (parent));
-  g_return_if_fail (glade_project_has_object (project,
-                                              glade_widget_get_object (parent)));
+/* translators: refers to a property '%s' of widget '[%s]' in toolkit version '%s %d.%d' */
+#define PACK_PROP_VERSION_CONFLICT_FMT _("[%s] Packing property '%s' of object class '%s' " \
+                                         "was introduced in %s %d.%d\n")
 
-  new_order = glade_widget_get_children (parent);
+#define PROP_DEPRECATED_MSG            _("This property is deprecated")
 
-  /* Check if the list changed */
-  for (l = old_order, ll = new_order; 
-       l && ll; 
-       l = g_list_next (l), ll = g_list_next (ll))
-    {
-      if (l->data != ll->data)
-        break;
-    }
+/* translators: refers to a property '%s' of widget '[%s]' */
+#define PROP_DEPRECATED_FMT            _("[%s] Property '%s' of object class '%s' is deprecated")
 
-  if (l || ll)
-    {
-      gint *order = g_new0 (gint, g_list_length (new_order));
-      GtkTreePath *path;
-      GtkTreeIter iter;
-      gint i;
-
-      for (i = 0, l = new_order; l; l = g_list_next (l))
-        {
-          GObject *obj = l->data;
-          GList *node = g_list_find (old_order, obj);
-
-          g_assert (node);
-
-          order[i] = g_list_position (old_order, node);
-          i++;
-        }
+/* translators: refers to a signal in toolkit version '%s %d.%d' 
+ * and a project targeting toolkit version '%s %d.%d' */
+#define SIGNAL_VERSION_CONFLICT_MSGFMT _("This signal was introduced in %s %d.%d " \
+                                         "while project targets %s %d.%d")
 
-      /* Signal that the rows were reordered */
-      glade_project_model_get_iter_for_object (project, glade_widget_get_object (parent), &iter);
-      path = gtk_tree_model_get_path (GTK_TREE_MODEL (project), &iter);
-      gtk_tree_model_rows_reordered (GTK_TREE_MODEL (project), path, &iter, order);
-      gtk_tree_path_free (path);
+/* translators: refers to a signal '%s' of widget '[%s]' in toolkit version '%s %d.%d' */
+#define SIGNAL_VERSION_CONFLICT_FMT    _("[%s] Signal '%s' of object class '%s' " \
+                                         "was introduced in %s %d.%d\n")
 
-      g_free (order);
-    }
+#define SIGNAL_DEPRECATED_MSG          _("This signal is deprecated")
 
-  g_list_free (new_order);
-}
+/* translators: refers to a signal '%s' of widget '[%s]' */
+#define SIGNAL_DEPRECATED_FMT          _("[%s] Signal '%s' of object class '%s' is deprecated")
 
-static inline gboolean
-glade_project_has_gwidget (GladeProject *project, GladeWidget *gwidget)
-{
-  return (glade_widget_get_project (gwidget) == project && 
-           glade_widget_in_project (gwidget));
-}
 
-/**
- * glade_project_add_object:
- * @project: the #GladeProject the widget is added to
- * @object: the #GObject to add
- *
- * Adds an object to the project.
- */
-void
-glade_project_add_object (GladeProject *project, GObject *object)
+static void
+glade_project_verify_property_internal (GladeProject *project,
+                                        GladeProperty *property,
+                                        const gchar *path_name,
+                                        GString *string,
+                                        gboolean forwidget,
+                                       GladeVerifyFlags flags)
 {
-  GladeProjectPrivate *priv;
-  GladeWidget *gwidget;
-  GList *list, *children;
-  const gchar *name;
-
-  g_return_if_fail (GLADE_IS_PROJECT (project));
-  g_return_if_fail (G_IS_OBJECT (object));
-
-  /* We don't list placeholders */
-  if (GLADE_IS_PLACEHOLDER (object))
-    return;
+  GladeWidgetAdaptor *adaptor, *prop_adaptor;
+  GladePropertyClass *pclass;
+  GParamSpec         *pspec;
+  gint target_major, target_minor;
+  gchar *catalog, *tooltip;
 
-  /* Only widgets accounted for in the catalog or widgets declared
-   * in the plugin with glade_widget_new_for_internal_child () are
-   * usefull in the project.
+  /* For verification lists, we're only interested in verifying the 'used' state of properties.
+   *
+   * For the UI on the other hand, we want to show warnings on unset properties until they
+   * are set.
    */
-  if ((gwidget = glade_widget_get_from_gobject (object)) == NULL)
+  if (!forwidget && (glade_property_get_state (property) & GLADE_STATE_CHANGED) == 0)
     return;
 
-  if (glade_project_has_gwidget (project, gwidget))
-    {
-      /* FIXME: It's possible we need to notify the model iface if this 
-       * happens to make sure the hierarchy is the same, I dont know, this 
-       * happens when message dialogs with children are rebuilt but the 
-       * hierarchy still looks good afterwards. */
-      return;
-    }
+  pclass       = glade_property_get_class (property);
+  pspec        = glade_property_class_get_pspec (pclass);
+  prop_adaptor = glade_property_class_get_adaptor (pclass);
+  adaptor      = glade_widget_adaptor_from_pspec (prop_adaptor, pspec);
 
-  priv = project->priv;
-  
-  name = glade_widget_get_name (gwidget);
-  /* Make sure we have an exclusive name first... */
-  if (!glade_project_available_widget_name (project, gwidget, name))
-    {
-      gchar *new_name = glade_project_new_widget_name (project, gwidget, name);
+  g_object_get (adaptor, "catalog", &catalog, NULL);
+  glade_project_target_version_for_adaptor (project, adaptor,
+                                            &target_major, &target_minor);
 
-      /* XXX Collect these errors and make a report at startup time */
-      if (priv->loading)
-        g_warning ("Loading object '%s' with name conflict, renaming to '%s'",
-                   name, new_name);
+  if ((flags & GLADE_VERIFY_VERSIONS) != 0 &&
+      !GPC_VERSION_CHECK (pclass, target_major, target_minor))
+    {
+      if (forwidget)
+        {
+          tooltip = g_strdup_printf (PROP_VERSION_CONFLICT_MSGFMT,
+                                     catalog,
+                                     glade_property_class_since_major (pclass),
+                                     glade_property_class_since_minor (pclass),
+                                     catalog, target_major, target_minor);
 
-      glade_widget_set_name (gwidget, new_name);
-      name = glade_widget_get_name (gwidget);
-      
-      g_free (new_name);
+          glade_property_set_support_warning (property, FALSE, tooltip);
+          g_free (tooltip);
+        }
+      else
+        g_string_append_printf (string,
+                                glade_property_class_get_is_packing (pclass) ?
+                                PACK_PROP_VERSION_CONFLICT_FMT :
+                                  PROP_VERSION_CONFLICT_FMT,
+                                  path_name,
+                                  glade_property_class_get_name (pclass),
+                                  glade_widget_adaptor_get_title (adaptor),
+                                  catalog,
+                                  glade_property_class_since_major (pclass),
+                                  glade_property_class_since_minor (pclass));
     }
-
-  glade_project_reserve_widget_name (project, gwidget, name);
-
-  glade_widget_set_project (gwidget, (gpointer) project);
-  glade_widget_set_in_project (gwidget, TRUE);
-  g_object_ref_sink (gwidget);
-
-  /* Be sure to update the lists before emitting signals */
-  if (glade_widget_get_parent (gwidget) == NULL)
-    priv->tree = g_list_append (priv->tree, object);
-
-  priv->objects = g_list_prepend (priv->objects, object);
-
-  glade_project_notify_row_inserted (project, gwidget);
-
-  /* NOTE: Sensitive ordering here, we need to recurse after updating
-   * the tree model listeners (and update those listeners after our
-   * internal lists have been resolved), otherwise children are added
-   * before the parents (and the views dont like that).
-   */
-  if ((children = glade_widget_get_children (gwidget)) != NULL)
+  else if ((flags & GLADE_VERIFY_DEPRECATIONS) != 0 &&
+          glade_property_class_deprecated (pclass))
     {
-      for (list = children; list && list->data; list = list->next)
-        glade_project_add_object (project, G_OBJECT (list->data));
-      g_list_free (children);
+      if (forwidget)
+       glade_property_set_support_warning (property, FALSE, PROP_DEPRECATED_MSG);
+      else
+        g_string_append_printf (string,
+                                PROP_DEPRECATED_FMT,
+                                path_name,
+                               glade_property_class_get_name (pclass),
+                                glade_widget_adaptor_get_title (adaptor));
     }
+  else if (forwidget)
+    glade_property_set_support_warning (property, FALSE, NULL);
 
-  /* Update user visible compatibility info */
-  glade_project_verify_properties (gwidget);
-
-  g_signal_emit (G_OBJECT (project),
-                 glade_project_signals[ADD_WIDGET], 0, gwidget);
-}
-
-/**
- * glade_project_has_object:
- * @project: the #GladeProject the widget is added to
- * @object: the #GObject to search
- *
- * Returns: whether this object is in this project.
- */
-gboolean
-glade_project_has_object (GladeProject *project, GObject *object)
-{
-  GladeWidget *gwidget;
-
-  g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
-  g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
-
-  gwidget = glade_widget_get_from_gobject (object);
-
-  g_return_val_if_fail (GLADE_IS_WIDGET (gwidget), FALSE);
-
-  return glade_project_has_gwidget (project, gwidget);
+  g_free (catalog);
 }
 
-void
-glade_project_widget_changed (GladeProject *project, GladeWidget *gwidget)
+static void
+glade_project_verify_properties_internal (GladeWidget *widget,
+                                          const gchar *path_name,
+                                          GString *string,
+                                          gboolean forwidget,
+                                         GladeVerifyFlags flags)
 {
-  GObject     *object;
-  GtkTreeIter  iter;
-  GtkTreePath *path;
-
-  g_return_if_fail (GLADE_IS_PROJECT (project));
-  g_return_if_fail (GLADE_IS_WIDGET (gwidget));
+  GList *list;
+  GladeProperty *property;
 
-  object = glade_widget_get_object (gwidget);
-  g_return_if_fail (glade_project_has_object (project, object));
+  for (list = glade_widget_get_properties (widget); list; list = list->next)
+    {
+      property = list->data;
+      glade_project_verify_property_internal (glade_widget_get_project (widget), 
+                                              property, path_name,
+                                              string, forwidget, flags);
+    }
 
-  glade_project_model_get_iter_for_object (project, object, &iter);
-  path = gtk_tree_model_get_path (GTK_TREE_MODEL (project), &iter);
-  gtk_tree_model_row_changed (GTK_TREE_MODEL (project), path, &iter);
-  gtk_tree_path_free (path);
+  /* Sometimes widgets on the clipboard have packing props with no parent */
+  if (glade_widget_get_parent (widget))
+    {
+      for (list = glade_widget_get_packing_properties (widget); list; list = list->next)
+        {
+          property = list->data;
+          glade_project_verify_property_internal (glade_widget_get_project (widget), 
+                                                  property, path_name, string, forwidget, flags);
+        }
+    }
 }
 
-/**
- * glade_project_remove_object:
- * @project: a #GladeProject
- * @object: the #GObject to remove
- *
- * Removes @object from @project.
- *
- * Note that when removing the #GObject from the project we
- * don't change ->project in the associated #GladeWidget; this
- * way UNDO can work.
- */
-void
-glade_project_remove_object (GladeProject *project, GObject *object)
+static void
+glade_project_verify_signal_internal (GladeWidget *widget,
+                                      GladeSignal *signal,
+                                      const gchar *path_name,
+                                      GString *string,
+                                      gboolean forwidget,
+                                     GladeVerifyFlags flags)
 {
-  GladeWidget *gwidget;
-  GList *list, *children;
-  gchar *preview_pid;
+  GladeSignalClass   *signal_class;
+  GladeWidgetAdaptor *adaptor;
+  gint                target_major, target_minor;
+  gchar              *catalog;
 
-  g_return_if_fail (GLADE_IS_PROJECT (project));
-  g_return_if_fail (G_IS_OBJECT (object));
+  signal_class =
+      glade_widget_adaptor_get_signal_class (glade_widget_get_adaptor (widget),
+                                             glade_signal_get_name (signal));
 
-  if (!glade_project_has_object (project, object))
+  if (!signal_class)
     return;
 
-  if (GLADE_IS_PLACEHOLDER (object))
-    return;
+  adaptor = glade_signal_class_get_adaptor (signal_class);
 
-  if ((gwidget = glade_widget_get_from_gobject (object)) == NULL)
-    return;
+  g_object_get (adaptor, "catalog", &catalog, NULL);
+  glade_project_target_version_for_adaptor (glade_widget_get_project (widget),
+                                            adaptor,
+                                            &target_major, &target_minor);
 
-  /* Recurse and remove deepest children first */
-  if ((children = glade_widget_get_children (gwidget)) != NULL)
+  if ((flags & GLADE_VERIFY_VERSIONS) != 0 &&
+      !GSC_VERSION_CHECK (signal_class, target_major, target_minor))
     {
-      for (list = children; list && list->data; list = list->next)
-        glade_project_remove_object (project, G_OBJECT (list->data));
-      g_list_free (children);
-    }
-
-  /* Notify views that the row is being deleted *before* deleting it */
-  glade_project_notify_row_deleted (project, gwidget);
-
-  /* Remove selection and release name from the name context */
-  glade_project_selection_remove (project, object, TRUE);
-  glade_project_release_widget_name (project, gwidget,
-                                     glade_widget_get_name (gwidget));
-
-  g_signal_emit (G_OBJECT (project),
-                 glade_project_signals[REMOVE_WIDGET], 0, gwidget);
-
-  /* Update internal data structure (remove from lists) */
-  project->priv->tree = g_list_remove (project->priv->tree, object);
-  project->priv->objects = g_list_remove (project->priv->objects, object);
+      if (forwidget)
+        {
+          gchar *warning;
 
-  if ((preview_pid = g_object_get_data (G_OBJECT (gwidget), "preview")))
-    g_hash_table_remove (project->priv->previews, preview_pid);
-  
-  /* Unset the project pointer on the GladeWidget */
-  glade_widget_set_project (gwidget, NULL);
-  glade_widget_set_in_project (gwidget, FALSE);
+          warning = g_strdup_printf (SIGNAL_VERSION_CONFLICT_MSGFMT,
+                                     catalog,
+                                     glade_signal_class_since_major (signal_class),
+                                     glade_signal_class_since_minor (signal_class),
+                                     catalog, target_major, target_minor);
+          glade_signal_set_support_warning (signal, warning);
+          g_free (warning);
+        }
+      else
+        g_string_append_printf (string,
+                                SIGNAL_VERSION_CONFLICT_FMT,
+                                path_name,
+                                glade_signal_get_name (signal),
+                                glade_widget_adaptor_get_title (adaptor),
+                                catalog,
+                                glade_signal_class_since_major (signal_class),
+                                glade_signal_class_since_minor (signal_class));
+    }
+  else if ((flags & GLADE_VERIFY_DEPRECATIONS) != 0 &&
+          glade_signal_class_deprecated (signal_class))
+    {
+      if (forwidget)
+       glade_signal_set_support_warning (signal, SIGNAL_DEPRECATED_MSG);
+      else
+        g_string_append_printf (string,
+                                SIGNAL_DEPRECATED_FMT,
+                                path_name,
+                                glade_signal_get_name (signal),
+                                glade_widget_adaptor_get_title (adaptor));
+    }
+  else if (forwidget)
+    glade_signal_set_support_warning (signal, NULL);
 
-  glade_project_notify_row_has_child (project, gwidget, FALSE);
-  g_object_unref (gwidget);
+  g_free (catalog);
 }
 
-/*******************************************************************
-                        Remaining stubs and api
- *******************************************************************/
 void
-glade_project_set_target_version (GladeProject *project,
-                                  const gchar *catalog,
-                                  gint major,
-                                  gint minor)
+glade_project_verify_property (GladeProperty *property)
 {
-  GladeTargetableVersion *version;
-  GSList *radios, *list;
-  GtkWidget *radio;
-
-  g_return_if_fail (GLADE_IS_PROJECT (project));
-  g_return_if_fail (catalog && catalog[0]);
-  g_return_if_fail (major >= 0);
-  g_return_if_fail (minor >= 0);
-
-  g_hash_table_insert (project->priv->target_versions_major,
-                       g_strdup (catalog), GINT_TO_POINTER ((int) major));
-  g_hash_table_insert (project->priv->target_versions_minor,
-                       g_strdup (catalog), GINT_TO_POINTER ((int) minor));
-
-  /* Update prefs dialog from here... */
-  if (project->priv->target_radios &&
-      (radios =
-       g_hash_table_lookup (project->priv->target_radios, catalog)) != NULL)
-    {
-      for (list = radios; list; list = list->next)
-        g_signal_handlers_block_by_func (G_OBJECT (list->data),
-                                         G_CALLBACK (target_button_clicked),
-                                         project);
-
-      for (list = radios; list; list = list->next)
-        {
-          radio = list->data;
+  GladeWidget  *widget;
+  GladeProject *project;
 
-          version = g_object_get_data (G_OBJECT (radio), "version");
-          if (version->major == major && version->minor == minor)
-            {
-              gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio), TRUE);
-              break;
-            }
-        }
+  g_return_if_fail (GLADE_IS_PROPERTY (property));
 
-      for (list = radios; list; list = list->next)
-        g_signal_handlers_unblock_by_func (G_OBJECT (list->data),
-                                           G_CALLBACK (target_button_clicked),
-                                           project);
-    }
+  widget  = glade_property_get_widget (property);
+  project = glade_widget_get_project (widget);
 
-  glade_project_verify_project_for_ui (project);
+  if (project)
+    glade_project_verify_property_internal (project, property, NULL, NULL, TRUE,
+                                           GLADE_VERIFY_VERSIONS     |
+                                           GLADE_VERIFY_DEPRECATIONS |
+                                           GLADE_VERIFY_UNRECOGNIZED);
+}
 
-  g_signal_emit (project, glade_project_signals[TARGETS_CHANGED], 0);
+void
+glade_project_verify_signal (GladeWidget *widget, GladeSignal *signal)
+{
+  glade_project_verify_signal_internal (widget, signal, NULL, NULL, TRUE,
+                                       GLADE_VERIFY_VERSIONS     |
+                                       GLADE_VERIFY_DEPRECATIONS |
+                                       GLADE_VERIFY_UNRECOGNIZED);
 }
 
 static void
-glade_project_set_readonly (GladeProject *project, gboolean readonly)
+glade_project_verify_signals (GladeWidget *widget,
+                              const gchar *path_name,
+                              GString *string,
+                              gboolean forwidget,
+                             GladeVerifyFlags flags)
 {
-  g_assert (GLADE_IS_PROJECT (project));
+  GladeSignal *signal;
+  GList *signals, *list;
 
-  if (project->priv->readonly != readonly)
+  if ((signals = glade_widget_get_signal_list (widget)) != NULL)
     {
-      project->priv->readonly = readonly;
-      g_object_notify_by_pspec (G_OBJECT (project), properties[PROP_READ_ONLY]);
+      for (list = signals; list; list = list->next)
+        {
+          signal = list->data;
+          glade_project_verify_signal_internal (widget, signal, path_name,
+                                                string, forwidget, flags);
+        }
+      g_list_free (signals);
     }
 }
 
 
 /**
- * glade_project_get_target_version:
- * @project: a #GladeProject
- * @catalog: the name of the catalog @project includes
- * @major: the return location for the target major version
- * @minor: the return location for the target minor version
- *
- * Fetches the target version of the @project for @catalog.
- *
- */
-void
-glade_project_get_target_version (GladeProject *project,
-                                  const gchar *catalog,
-                                  gint *major,
-                                  gint *minor)
-{
-  g_return_if_fail (GLADE_IS_PROJECT (project));
-  g_return_if_fail (catalog && catalog[0]);
-  g_return_if_fail (major && minor);
-
-  *major = GPOINTER_TO_INT
-      (g_hash_table_lookup (project->priv->target_versions_major, catalog));
-  *minor = GPOINTER_TO_INT
-      (g_hash_table_lookup (project->priv->target_versions_minor, catalog));
-}
-
-/**
- * glade_project_get_readonly:
- * @project: a #GladeProject
- *
- * Gets whether the project is read only or not
+ * glade_project_verify_properties:
+ * @widget: A #GladeWidget
  *
- * Returns: TRUE if project is read only
+ * Synchonizes @widget with user visible information
+ * about version compatability and notifies the UI
+ * it should update.
  */
-gboolean
-glade_project_get_readonly (GladeProject *project)
+static void
+glade_project_verify_properties (GladeWidget *widget)
 {
-  g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
-
-  return project->priv->readonly;
-}
+  GladeProject *project;
 
+  g_return_if_fail (GLADE_IS_WIDGET (widget));
 
-/**
- * glade_project_selection_changed:
- * @project: a #GladeProject
- *
- * Causes @project to emit a "selection_changed" signal.
- */
-void
-glade_project_selection_changed (GladeProject *project)
-{
-  g_return_if_fail (GLADE_IS_PROJECT (project));
+  project = glade_widget_get_project (widget);
+  if (!project || project->priv->loading)
+    return;
 
-  g_signal_emit (G_OBJECT (project),
-                 glade_project_signals[SELECTION_CHANGED], 0);
+  glade_project_verify_properties_internal (widget, NULL, NULL, TRUE,
+                                           GLADE_VERIFY_VERSIONS     |
+                                           GLADE_VERIFY_DEPRECATIONS |
+                                           GLADE_VERIFY_UNRECOGNIZED);
+  glade_project_verify_signals (widget, NULL, NULL, TRUE,
+                               GLADE_VERIFY_VERSIONS     |
+                               GLADE_VERIFY_DEPRECATIONS |
+                               GLADE_VERIFY_UNRECOGNIZED);
 
-  /* Cancel any idle we have */
-  if (project->priv->selection_changed_id > 0)
-    project->priv->selection_changed_id = 
-      (g_source_remove (project->priv->selection_changed_id), 0);
+  glade_widget_support_changed (widget);
 }
 
 static gboolean
-selection_change_idle (GladeProject *project)
+glade_project_verify_dialog (GladeProject *project,
+                             GString *string,
+                            gboolean saving)
 {
-  project->priv->selection_changed_id = 0;
-  glade_project_selection_changed (project);
-  return FALSE;
-}
+  GtkWidget *swindow;
+  GtkWidget *textview;
+  GtkWidget *expander;
+  GtkTextBuffer *buffer;
+  gchar *name;
+  gboolean ret;
 
-void
-glade_project_queue_selection_changed (GladeProject *project)
-{
-  g_return_if_fail (GLADE_IS_PROJECT (project));
+  swindow = gtk_scrolled_window_new (NULL, NULL);
+  textview = gtk_text_view_new ();
+  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
+  expander = gtk_expander_new (_("Details"));
 
-  if (project->priv->selection_changed_id == 0)
-    project->priv->selection_changed_id = 
-      g_idle_add ((GSourceFunc) selection_change_idle, project);
-}
+  gtk_text_buffer_set_text (buffer, string->str, -1);
 
-static void
-glade_project_set_has_selection (GladeProject *project, gboolean has_selection)
-{
-  g_assert (GLADE_IS_PROJECT (project));
+  gtk_container_add (GTK_CONTAINER (swindow), textview);
+  gtk_container_add (GTK_CONTAINER (expander), swindow);
+  gtk_widget_show_all (expander);
 
-  if (project->priv->has_selection != has_selection)
-    {
-      project->priv->has_selection = has_selection;
-      g_object_notify_by_pspec (G_OBJECT (project), properties[PROP_HAS_SELECTION]);
-    }
-}
+  gtk_widget_set_size_request (swindow, 800, -1);
 
-/**
- * glade_project_get_has_selection:
- * @project: a #GladeProject
- *
- * Returns: whether @project currently has a selection
- */
-gboolean
-glade_project_get_has_selection (GladeProject *project)
-{
-  g_assert (GLADE_IS_PROJECT (project));
+  name = glade_project_get_name (project);
+  ret = glade_util_ui_message (glade_app_get_window (),
+                               saving ? GLADE_UI_YES_OR_NO : GLADE_UI_INFO,
+                               expander,
+                               saving ?
+                               _("Project \"%s\" has errors. Save anyway?") :
+                               _("Project \"%s\" has deprecated widgets "
+                                 "and/or version mismatches."), name);
+  g_free (name);
 
-  return project->priv->has_selection;
+  return ret;
 }
 
-/**
- * glade_project_is_selected:
- * @project: a #GladeProject
- * @object: a #GObject
- *
- * Returns: whether @object is in @project selection
- */
-gboolean
-glade_project_is_selected (GladeProject *project, GObject *object)
-{
-  g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
-  return (g_list_find (project->priv->selection, object)) != NULL;
-}
 
-/**
- * glade_project_selection_clear:
- * @project: a #GladeProject
- * @emit_signal: whether or not to emit a signal indication a selection change
- *
- * Clears @project's selection chain
- *
- * If @emit_signal is %TRUE, calls glade_project_selection_changed().
- */
-void
-glade_project_selection_clear (GladeProject *project, gboolean emit_signal)
+gboolean
+glade_project_verify (GladeProject *project, gboolean saving, GladeVerifyFlags flags)
 {
-  GList *l;
-
-  g_return_if_fail (GLADE_IS_PROJECT (project));
+  GString *string = g_string_new (NULL);
+  GList *list;
+  gboolean ret = TRUE;
+  
+  for (list = project->priv->objects; list; list = list->next)
+    {
+      GladeWidget *widget = glade_widget_get_from_gobject (list->data);
+      
+      if ((flags & GLADE_VERIFY_UNRECOGNIZED) != 0 &&
+         GLADE_IS_OBJECT_STUB (list->data))
+        {
+          gchar *type;
+          g_object_get (list->data, "object-type", &type, NULL);
+          
+          g_string_append_printf (string, _("Object %s has unrecognized type %s\n"), 
+                                  glade_widget_get_name (widget), type);
+          g_free (type);
+        }
+      else
+        {
+          gchar *path_name = glade_widget_generate_path_name (widget);
 
-  if (project->priv->selection == NULL)
-    return;
+          glade_project_verify_adaptor (project, glade_widget_get_adaptor (widget),
+                                        path_name, string, flags, FALSE, NULL);
+          glade_project_verify_properties_internal (widget, path_name, string, FALSE, flags);
+          glade_project_verify_signals (widget, path_name, string, FALSE, flags);
 
-  for (l = project->priv->selection; l; l = l->next)
-    {
-      if (GTK_IS_WIDGET (l->data))
-        gtk_widget_queue_draw (GTK_WIDGET (l->data));
+          g_free (path_name);
+        }
     }
 
-  g_list_free (project->priv->selection);
-  project->priv->selection = NULL;
-  glade_project_set_has_selection (project, FALSE);
-
-  if (emit_signal)
-    glade_project_selection_changed (project);
-}
+  if (string->len > 0)
+    {
+      ret = glade_project_verify_dialog (project, string, saving);
 
-/**
- * glade_project_selection_remove:
- * @project: a #GladeProject
- * @object:  a #GObject in @project
- * @emit_signal: whether or not to emit a signal 
- *               indicating a selection change
- *
- * Removes @object from the selection chain of @project
- *
- * If @emit_signal is %TRUE, calls glade_project_selection_changed().
- */
-void
-glade_project_selection_remove (GladeProject *project,
-                                GObject *object,
-                                gboolean emit_signal)
+      if (!saving)
+        ret = FALSE;
+    }
+
+  g_string_free (string, TRUE);
+
+  return ret;
+}
+
+static void
+glade_project_target_version_for_adaptor (GladeProject *project,
+                                          GladeWidgetAdaptor *adaptor,
+                                          gint *major,
+                                          gint *minor)
 {
-  g_return_if_fail (GLADE_IS_PROJECT (project));
-  g_return_if_fail (G_IS_OBJECT (object));
+  gchar *catalog = NULL;
 
-  if (glade_project_is_selected (project, object))
-    {
-      project->priv->selection =
-          g_list_remove (project->priv->selection, object);
-      if (project->priv->selection == NULL)
-        glade_project_set_has_selection (project, FALSE);
-      if (emit_signal)
-        glade_project_selection_changed (project);
-    }
+  g_object_get (adaptor, "catalog", &catalog, NULL);
+  glade_project_get_target_version (project, catalog, major, minor);
+  g_free (catalog);
 }
 
-/**
- * glade_project_selection_add:
- * @project: a #GladeProject
- * @object:  a #GObject in @project
- * @emit_signal: whether or not to emit a signal indicating 
- *               a selection change
- *
- * Adds @object to the selection chain of @project
- *
- * If @emit_signal is %TRUE, calls glade_project_selection_changed().
- */
-void
-glade_project_selection_add (GladeProject *project,
-                             GObject *object,
-                             gboolean emit_signal)
+static void
+glade_project_verify_adaptor (GladeProject *project,
+                              GladeWidgetAdaptor *adaptor,
+                              const gchar *path_name,
+                              GString *string,
+                              GladeVerifyFlags flags,
+                              gboolean forwidget,
+                              GladeSupportMask *mask)
 {
-  g_return_if_fail (GLADE_IS_PROJECT (project));
-  g_return_if_fail (G_IS_OBJECT (object));
-  g_return_if_fail (glade_project_has_object (project, object));
+  GladeSupportMask support_mask = GLADE_SUPPORT_OK;
+  GladeWidgetAdaptor *adaptor_iter;
+  gint target_major, target_minor;
+  gchar *catalog = NULL;
 
-  if (glade_project_is_selected (project, object) == FALSE)
+  for (adaptor_iter = adaptor; adaptor_iter && support_mask == GLADE_SUPPORT_OK;
+       adaptor_iter = glade_widget_adaptor_get_parent_adaptor (adaptor_iter))
     {
-      gboolean toggle_has_selection = (project->priv->selection == NULL);
 
-      if (GTK_IS_WIDGET (object))
-        gtk_widget_queue_draw (GTK_WIDGET (object));
+      g_object_get (adaptor_iter, "catalog", &catalog, NULL);
+      glade_project_target_version_for_adaptor (project, adaptor_iter,
+                                                &target_major, &target_minor);
 
-      project->priv->selection =
-        g_list_prepend (project->priv->selection, object);
+      /* Only one versioning message (builder or otherwise)...
+       */
+      if ((flags & GLADE_VERIFY_VERSIONS) != 0 &&
+         !GWA_VERSION_CHECK (adaptor_iter, target_major, target_minor))
+        {
+          if (forwidget)
+            g_string_append_printf (string,
+                                    WIDGET_VERSION_CONFLICT_MSGFMT,
+                                    catalog,
+                                    GWA_VERSION_SINCE_MAJOR (adaptor_iter),
+                                    GWA_VERSION_SINCE_MINOR (adaptor_iter),
+                                    catalog, target_major, target_minor);
+          else
+            g_string_append_printf (string,
+                                    WIDGET_VERSION_CONFLICT_FMT,
+                                    path_name, 
+                                    glade_widget_adaptor_get_title (adaptor_iter),
+                                    catalog,
+                                    GWA_VERSION_SINCE_MAJOR (adaptor_iter),
+                                    GWA_VERSION_SINCE_MINOR (adaptor_iter));
 
-      if (toggle_has_selection)
-        glade_project_set_has_selection (project, TRUE);
+          support_mask |= GLADE_SUPPORT_MISMATCH;
+        }
 
-      if (emit_signal)
-        glade_project_selection_changed (project);
+      if ((flags & GLADE_VERIFY_DEPRECATIONS) != 0 &&
+         GWA_DEPRECATED (adaptor_iter))
+        {
+          if (forwidget)
+            {
+              if (string->len)
+                g_string_append (string, "\n");
+
+              g_string_append_printf (string, WIDGET_DEPRECATED_MSG);
+            }
+          else
+            g_string_append_printf (string, WIDGET_DEPRECATED_FMT,
+                                    path_name, 
+                                    glade_widget_adaptor_get_title (adaptor_iter), 
+                                    catalog, target_major, target_minor);
+
+          support_mask |= GLADE_SUPPORT_DEPRECATED;
+        }
+      g_free (catalog);
     }
+  if (mask)
+    *mask = support_mask;
+
 }
 
 /**
- * glade_project_selection_set:
- * @project: a #GladeProject
- * @object:  a #GObject in @project
- * @emit_signal: whether or not to emit a signal 
- *               indicating a selection change
- *
- * Set the selection in @project to @object
+ * glade_project_verify_widget_adaptor:
+ * @project: A #GladeProject
+ * @adaptor: the #GladeWidgetAdaptor to verify
+ * @mask: a return location for a #GladeSupportMask
+ * 
+ * Checks the supported state of this widget adaptor
+ * and generates a string to show in the UI describing why.
  *
- * If @emit_signal is %TRUE, calls glade_project_selection_changed().
+ * Returns: A newly allocated string 
  */
-void
-glade_project_selection_set (GladeProject *project,
-                             GObject *object,
-                             gboolean emit_signal)
+gchar *
+glade_project_verify_widget_adaptor (GladeProject *project,
+                                     GladeWidgetAdaptor *adaptor,
+                                     GladeSupportMask *mask)
 {
-  g_return_if_fail (GLADE_IS_PROJECT (project));
-  g_return_if_fail (G_IS_OBJECT (object));
-  g_return_if_fail (glade_project_has_object (project, object));
+  GString *string = g_string_new (NULL);
+  gchar *ret = NULL;
 
-  if (glade_project_is_selected (project, object) == FALSE ||
-      g_list_length (project->priv->selection) != 1)
+  glade_project_verify_adaptor (project, adaptor, NULL,
+                                string,
+                               GLADE_VERIFY_VERSIONS     |
+                               GLADE_VERIFY_DEPRECATIONS |
+                               GLADE_VERIFY_UNRECOGNIZED,
+                               TRUE, mask);
+
+  /* there was a '\0' byte... */
+  if (string->len > 0)
     {
-      glade_project_selection_clear (project, FALSE);
-      glade_project_selection_add (project, object, emit_signal);
+      ret = string->str;
+      g_string_free (string, FALSE);
     }
-}
+  else
+    g_string_free (string, TRUE);
 
-/**
- * glade_project_selection_get:
- * @project: a #GladeProject
- *
- * Returns: a #GList containing the #GtkWidget items currently selected in @project
- */
-GList *
-glade_project_selection_get (GladeProject *project)
-{
-  g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
 
-  return project->priv->selection;
+  return ret;
 }
 
+
 /**
- * glade_project_required_libs:
- * @project: a #GladeProject
- *
- * Returns: a #GList of allocated strings which are the names
- * of the required catalogs for this project
+ * glade_project_verify_project_for_ui:
+ * @project: A #GladeProject
+ * 
+ * Checks the project and updates warning strings in the UI
  */
-GList *
-glade_project_required_libs (GladeProject *project)
+static void
+glade_project_verify_project_for_ui (GladeProject *project)
 {
-  GList *required = NULL, *l, *ll;
-  GladeWidget *gwidget;
-  gboolean listed;
+  GList *list;
+  GladeWidget *widget;
 
-  for (l = project->priv->objects; l; l = l->next)
+  /* Sync displayable info here */
+  for (list = project->priv->objects; list; list = list->next)
     {
-      gchar *catalog = NULL;
-
-      gwidget = glade_widget_get_from_gobject (l->data);
-      g_assert (gwidget);
-
-      g_object_get (glade_widget_get_adaptor (gwidget), "catalog", &catalog, NULL);
-
-      if (catalog)
-        {
-          listed = FALSE;
-          for (ll = required; ll; ll = ll->next)
-            if (!strcmp ((gchar *) ll->data, catalog))
-              {
-                listed = TRUE;
-                break;
-              }
-
-          if (!listed)
-            required = g_list_prepend (required, catalog);
-        }
-    }
+      widget = glade_widget_get_from_gobject (list->data);
 
-  /* Assume GTK+ here */
-  if (!required)
-    required = g_list_prepend (required, g_strdup ("gtk+"));
+      /* Update the support warnings for widget's properties */
+      glade_project_verify_properties (widget);
 
-  required = g_list_reverse (required);
-    
-  for (l = project->priv->unknown_catalogs; l; l = g_list_next (l))
-    {
-      CatalogInfo *data = l->data;
-      /* Keep position to make sure we do not create a diff when saving */
-      required = g_list_insert (required, g_strdup (data->catalog), data->position);
+      /* Update the support warning for widget */
+      glade_widget_verify (widget);
     }
-  
-  return required;
 }
 
 /**
- * glade_project_undo:
+ * glade_project_get_widget_by_name:
  * @project: a #GladeProject
+ * @ancestor: The toplevel project object to search under
+ * @name: The user visible name of the widget we are looking for
  * 
- * Undoes a #GladeCommand in this project.
+ * Searches under @ancestor in @project looking for a #GladeWidget named @name.
+ * 
+ * Returns: a pointer to the widget, %NULL if the widget does not exist
  */
-void
-glade_project_undo (GladeProject *project)
+GladeWidget *
+glade_project_get_widget_by_name (GladeProject *project,
+                                  const gchar  *name)
 {
-  g_return_if_fail (GLADE_IS_PROJECT (project));
-  GLADE_PROJECT_GET_CLASS (project)->undo (project);
+  GList *list;
+
+  g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
+  g_return_val_if_fail (name != NULL, NULL);
+
+  for (list = project->priv->objects; list; list = list->next)
+    {
+      GladeWidget *widget;
+
+      widget = glade_widget_get_from_gobject (list->data);
+
+      if (strcmp (glade_widget_get_name (widget), name) == 0)
+        return widget;
+    }
+
+  return NULL;
 }
 
-/**
- * glade_project_undo:
- * @project: a #GladeProject
- * 
- * Redoes a #GladeCommand in this project.
- */
-void
-glade_project_redo (GladeProject *project)
+static void
+glade_project_release_widget_name (GladeProject *project,
+                                   GladeWidget *gwidget,
+                                   const char *widget_name)
 {
-  g_return_if_fail (GLADE_IS_PROJECT (project));
-  GLADE_PROJECT_GET_CLASS (project)->redo (project);
+  glade_name_context_release_name (project->priv->widget_names, widget_name);
 }
 
 /**
- * glade_project_next_undo_item:
+ * glade_project_available_widget_name:
  * @project: a #GladeProject
- * 
- * Gets the next undo item on @project's command stack.
+ * @widget: the #GladeWidget intended to recieve a new name
+ * @name: base name of the widget to create
  *
- * Returns: the #GladeCommand
+ * Checks whether @name is an appropriate name for @widget.
+ *
+ * Returns: whether the name is available or not.
  */
-GladeCommand *
-glade_project_next_undo_item (GladeProject *project)
+gboolean
+glade_project_available_widget_name (GladeProject *project,
+                                     GladeWidget *widget,
+                                     const gchar *name)
 {
-  g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
-  return GLADE_PROJECT_GET_CLASS (project)->next_undo_item (project);
+  g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
+  g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
+
+  if (!name || !name[0])
+    return FALSE;
+
+  return !glade_name_context_has_name (project->priv->widget_names, name);
 }
 
+static void
+glade_project_reserve_widget_name (GladeProject *project,
+                                   GladeWidget *gwidget,
+                                   const char *widget_name)
+{
+  if (!glade_project_available_widget_name (project, gwidget, widget_name))
+    {
+      g_warning ("BUG: widget '%s' attempting to reserve an unavailable widget name '%s' !",
+                 glade_widget_get_name (gwidget), widget_name);
+      return;
+    }
+
+  /* Add to name context */
+  glade_name_context_add_name (project->priv->widget_names, widget_name);
+}
 
 /**
- * glade_project_next_redo_item:
+ * glade_project_new_widget_name:
  * @project: a #GladeProject
- * 
- * Gets the next redo item on @project's command stack.
+ * @widget: the #GladeWidget intended to recieve a new name
+ * @base_name: base name of the widget to create
  *
- * Returns: the #GladeCommand
+ * Creates a new name for a widget that doesn't collide with any of the names 
+ * already in @project. This name will start with @base_name.
+ *
+ * Returns: a string containing the new name, %NULL if there is not enough 
+ *          memory for this string
  */
-GladeCommand *
-glade_project_next_redo_item (GladeProject *project)
+gchar *
+glade_project_new_widget_name (GladeProject *project,
+                               GladeWidget *widget,
+                               const gchar *base_name)
 {
+  gchar *name;
+
   g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
-  return GLADE_PROJECT_GET_CLASS (project)->next_redo_item (project);
-}
+  g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
+  g_return_val_if_fail (base_name && base_name[0], NULL);
 
+  name = glade_name_context_new_name (project->priv->widget_names, base_name);
 
+  return name;
+}
 
 /**
- * glade_project_push_undo:
+ * glade_project_set_widget_name:
  * @project: a #GladeProject
- * @cmd: the #GladeCommand
- * 
- * Pushes a newly created #GladeCommand onto @projects stack.
+ * @widget: the #GladeWidget to set a name on
+ * @name: the name to set.
+ *
+ * Sets @name on @widget in @project, if @name is not
+ * available then a new name will be used.
  */
 void
-glade_project_push_undo (GladeProject *project, GladeCommand *cmd)
+glade_project_set_widget_name (GladeProject *project,
+                               GladeWidget *widget,
+                               const gchar *name)
 {
-  g_return_if_fail (GLADE_IS_PROJECT (project));
-  g_return_if_fail (GLADE_IS_COMMAND (cmd));
+  gchar *new_name;
+  GtkTreeIter iter;
+  GtkTreePath *path;
 
-  GLADE_PROJECT_GET_CLASS (project)->push_undo (project, cmd);
-}
+  g_return_if_fail (GLADE_IS_PROJECT (project));
+  g_return_if_fail (GLADE_IS_WIDGET (widget));
+  g_return_if_fail (name && name[0]);
 
-static GList *
-walk_command (GList *list, gboolean forward)
-{
-  GladeCommand *cmd = list->data;
-  GladeCommand *next_cmd;
+  if (strcmp (name, glade_widget_get_name (widget)) == 0)
+    return;
 
-  if (forward)
-    list = list->next;
+  /* Police the widget name */
+  if (!glade_project_available_widget_name (project, widget, name))
+    new_name = glade_project_new_widget_name (project, widget, name);
   else
-    list = list->prev;
+    new_name = g_strdup (name);
 
-  next_cmd = list ? list->data : NULL;
+  glade_project_reserve_widget_name (project, widget, new_name);
 
-  while (list && 
-   glade_command_group_id (next_cmd) != 0 && 
-   glade_command_group_id (next_cmd) == glade_command_group_id (cmd))
-    {
-      if (forward)
-        list = list->next;
-      else
-        list = list->prev;
+  /* Release old name and set new widget name */
+  glade_project_release_widget_name (project, widget, glade_widget_get_name (widget));
+  glade_widget_set_name (widget, new_name);
 
-      if (list)
-        next_cmd = list->data;
-    }
+  g_signal_emit (G_OBJECT (project),
+                 glade_project_signals[WIDGET_NAME_CHANGED], 0, widget);
 
-  return list;
+  g_free (new_name);
+
+  /* Notify views about the iter change */
+  glade_project_model_get_iter_for_object (project, glade_widget_get_object (widget), &iter);
+  path = gtk_tree_model_get_path (GTK_TREE_MODEL (project), &iter);
+  gtk_tree_model_row_changed (GTK_TREE_MODEL (project), path, &iter);
+  gtk_tree_path_free (path);
 }
 
 static void
-undo_item_activated (GtkMenuItem *item, GladeProject *project)
+glade_project_notify_row_has_child (GladeProject *project,
+                                   GladeWidget  *gwidget,
+                                   gboolean      adding)
 {
-  gint index, next_index;
-
-  GladeCommand *cmd = g_object_get_data (G_OBJECT (item), "command-data");
-  GladeCommand *next_cmd;
-
-  index = g_list_index (project->priv->undo_stack, cmd);
+  GladeWidget *parent;
+  gint         siblings;
+       
+  parent = glade_widget_get_parent (gwidget);
 
-  do
+  if (parent)
     {
-      next_cmd = glade_project_next_undo_item (project);
-      next_index = g_list_index (project->priv->undo_stack, next_cmd);
+      siblings = glade_project_count_children (project, parent);
 
-      glade_project_undo (project);
+      if (siblings == (adding ? 1 : 0))
+       {
+         GtkTreePath *path;
+         GtkTreeIter  iter;
 
+         glade_project_model_get_iter_for_object (project, 
+                                                  glade_widget_get_object (parent), &iter);
+         path = gtk_tree_model_get_path (GTK_TREE_MODEL (project), &iter);
+         gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (project), path, &iter);
+         gtk_tree_path_free (path);
+       }
     }
-  while (next_index > index);
 }
 
 static void
-redo_item_activated (GtkMenuItem *item, GladeProject *project)
+glade_project_notify_row_inserted (GladeProject *project, GladeWidget *gwidget)
 {
-  gint index, next_index;
+  GtkTreeIter iter;
+  GtkTreePath *path;
 
-  GladeCommand *cmd = g_object_get_data (G_OBJECT (item), "command-data");
-  GladeCommand *next_cmd;
+  /* The state of old iters go invalid and then the new iter is valid
+   * until the next change */
+  project->priv->stamp++;
 
-  index = g_list_index (project->priv->undo_stack, cmd);
+  glade_project_model_get_iter_for_object (project, glade_widget_get_object (gwidget), &iter);
+  path = gtk_tree_model_get_path (GTK_TREE_MODEL (project), &iter);
+  gtk_tree_model_row_inserted (GTK_TREE_MODEL (project), path, &iter);
+  gtk_tree_path_free (path);
 
-  do
+  glade_project_notify_row_has_child (project, gwidget, TRUE);
+}
+
+static void
+glade_project_notify_row_deleted (GladeProject *project, GladeWidget *gwidget)
+{
+  GtkTreeIter iter;
+  GtkTreePath *path;
+
+  glade_project_model_get_iter_for_object (project, glade_widget_get_object (gwidget), &iter);
+  path = gtk_tree_model_get_path (GTK_TREE_MODEL (project), &iter);
+
+  gtk_tree_model_row_deleted (GTK_TREE_MODEL (project), path);
+  gtk_tree_path_free (path);
+
+  project->priv->stamp++;
+}
+
+void
+glade_project_check_reordered (GladeProject *project,
+                               GladeWidget  *parent,
+                               GList        *old_order)
+{
+  GList       *new_order, *l, *ll;
+
+  g_return_if_fail (GLADE_IS_PROJECT (project));
+  g_return_if_fail (GLADE_IS_WIDGET (parent));
+  g_return_if_fail (glade_project_has_object (project,
+                                              glade_widget_get_object (parent)));
+
+  new_order = glade_widget_get_children (parent);
+
+  /* Check if the list changed */
+  for (l = old_order, ll = new_order; 
+       l && ll; 
+       l = g_list_next (l), ll = g_list_next (ll))
     {
-      next_cmd = glade_project_next_redo_item (project);
-      next_index = g_list_index (project->priv->undo_stack, next_cmd);
+      if (l->data != ll->data)
+        break;
+    }
+
+  if (l || ll)
+    {
+      gint *order = g_new0 (gint, g_list_length (new_order));
+      GtkTreePath *path;
+      GtkTreeIter iter;
+      gint i;
+
+      for (i = 0, l = new_order; l; l = g_list_next (l))
+        {
+          GObject *obj = l->data;
+          GList *node = g_list_find (old_order, obj);
+
+          g_assert (node);
 
-      glade_project_redo (project);
+          order[i] = g_list_position (old_order, node);
+          i++;
+        }
+
+      /* Signal that the rows were reordered */
+      glade_project_model_get_iter_for_object (project, glade_widget_get_object (parent), &iter);
+      path = gtk_tree_model_get_path (GTK_TREE_MODEL (project), &iter);
+      gtk_tree_model_rows_reordered (GTK_TREE_MODEL (project), path, &iter, order);
+      gtk_tree_path_free (path);
 
+      g_free (order);
     }
-  while (next_index < index);
+
+  g_list_free (new_order);
 }
 
+static inline gboolean
+glade_project_has_gwidget (GladeProject *project, GladeWidget *gwidget)
+{
+  return (glade_widget_get_project (gwidget) == project && 
+           glade_widget_in_project (gwidget));
+}
 
 /**
- * glade_project_undo_items:
- * @project: A #GladeProject
- *
- * Creates a menu of the undo items in the project stack
+ * glade_project_add_object:
+ * @project: the #GladeProject the widget is added to
+ * @object: the #GObject to add
  *
- * Returns: A newly created menu
+ * Adds an object to the project.
  */
-GtkWidget *
-glade_project_undo_items (GladeProject *project)
+void
+glade_project_add_object (GladeProject *project, GObject *object)
 {
-  GtkWidget *menu = NULL;
-  GtkWidget *item;
-  GladeCommand *cmd;
-  GList *l;
+  GladeProjectPrivate *priv;
+  GladeWidget *gwidget;
+  GList *list, *children;
+  const gchar *name;
 
-  g_return_val_if_fail (project != NULL, NULL);
+  g_return_if_fail (GLADE_IS_PROJECT (project));
+  g_return_if_fail (G_IS_OBJECT (object));
 
-  for (l = project->priv->prev_redo_item; l; l = walk_command (l, FALSE))
+  /* We don't list placeholders */
+  if (GLADE_IS_PLACEHOLDER (object))
+    return;
+
+  /* Only widgets accounted for in the catalog or widgets declared
+   * in the plugin with glade_widget_new_for_internal_child () are
+   * usefull in the project.
+   */
+  if ((gwidget = glade_widget_get_from_gobject (object)) == NULL)
+    return;
+
+  if (glade_project_has_gwidget (project, gwidget))
     {
-      cmd = l->data;
+      /* FIXME: It's possible we need to notify the model iface if this 
+       * happens to make sure the hierarchy is the same, I dont know, this 
+       * happens when message dialogs with children are rebuilt but the 
+       * hierarchy still looks good afterwards. */
+      return;
+    }
 
-      if (!menu)
-        menu = gtk_menu_new ();
+  priv = project->priv;
+  
+  name = glade_widget_get_name (gwidget);
+  /* Make sure we have an exclusive name first... */
+  if (!glade_project_available_widget_name (project, gwidget, name))
+    {
+      gchar *new_name = glade_project_new_widget_name (project, gwidget, name);
 
-      item = gtk_menu_item_new_with_label (glade_command_description (cmd));
-      gtk_widget_show (item);
-      gtk_menu_shell_append (GTK_MENU_SHELL (menu), GTK_WIDGET (item));
-      g_object_set_data (G_OBJECT (item), "command-data", cmd);
+      /* XXX Collect these errors and make a report at startup time */
+      if (priv->loading)
+        g_warning ("Loading object '%s' with name conflict, renaming to '%s'",
+                   name, new_name);
 
-      g_signal_connect (G_OBJECT (item), "activate",
-                        G_CALLBACK (undo_item_activated), project);
+      glade_widget_set_name (gwidget, new_name);
+      name = glade_widget_get_name (gwidget);
+      
+      g_free (new_name);
+    }
+
+  glade_project_reserve_widget_name (project, gwidget, name);
+
+  glade_widget_set_project (gwidget, (gpointer) project);
+  glade_widget_set_in_project (gwidget, TRUE);
+  g_object_ref_sink (gwidget);
+
+  /* Be sure to update the lists before emitting signals */
+  if (glade_widget_get_parent (gwidget) == NULL)
+    priv->tree = g_list_append (priv->tree, object);
+
+  priv->objects = g_list_prepend (priv->objects, object);
+
+  glade_project_notify_row_inserted (project, gwidget);
 
+  /* NOTE: Sensitive ordering here, we need to recurse after updating
+   * the tree model listeners (and update those listeners after our
+   * internal lists have been resolved), otherwise children are added
+   * before the parents (and the views dont like that).
+   */
+  if ((children = glade_widget_get_children (gwidget)) != NULL)
+    {
+      for (list = children; list && list->data; list = list->next)
+        glade_project_add_object (project, G_OBJECT (list->data));
+      g_list_free (children);
     }
 
-  return menu;
+  /* Update user visible compatibility info */
+  glade_project_verify_properties (gwidget);
+
+  g_signal_emit (G_OBJECT (project),
+                 glade_project_signals[ADD_WIDGET], 0, gwidget);
 }
 
 /**
- * glade_project_redo_items:
- * @project: A #GladeProject
- *
- * Creates a menu of the undo items in the project stack
+ * glade_project_has_object:
+ * @project: the #GladeProject the widget is added to
+ * @object: the #GObject to search
  *
- * Returns: A newly created menu
+ * Returns: whether this object is in this project.
  */
-GtkWidget *
-glade_project_redo_items (GladeProject *project)
+gboolean
+glade_project_has_object (GladeProject *project, GObject *object)
 {
-  GtkWidget *menu = NULL;
-  GtkWidget *item;
-  GladeCommand *cmd;
-  GList *l;
-
-  g_return_val_if_fail (project != NULL, NULL);
-
-  for (l = project->priv->prev_redo_item ?
-       project->priv->prev_redo_item->next :
-       project->priv->undo_stack; l; l = walk_command (l, TRUE))
-    {
-      cmd = l->data;
-
-      if (!menu)
-        menu = gtk_menu_new ();
+  GladeWidget *gwidget;
 
-      item = gtk_menu_item_new_with_label (glade_command_description (cmd));
-      gtk_widget_show (item);
-      gtk_menu_shell_append (GTK_MENU_SHELL (menu), GTK_WIDGET (item));
-      g_object_set_data (G_OBJECT (item), "command-data", cmd);
+  g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
+  g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
 
-      g_signal_connect (G_OBJECT (item), "activate",
-                        G_CALLBACK (redo_item_activated), project);
+  gwidget = glade_widget_get_from_gobject (object);
 
-    }
+  g_return_val_if_fail (GLADE_IS_WIDGET (gwidget), FALSE);
 
-  return menu;
+  return glade_project_has_gwidget (project, gwidget);
 }
 
 void
-glade_project_reset_path (GladeProject *project)
+glade_project_widget_changed (GladeProject *project, GladeWidget *gwidget)
 {
+  GObject     *object;
+  GtkTreeIter  iter;
+  GtkTreePath *path;
+
   g_return_if_fail (GLADE_IS_PROJECT (project));
-  project->priv->path = (g_free (project->priv->path), NULL);
+  g_return_if_fail (GLADE_IS_WIDGET (gwidget));
+
+  object = glade_widget_get_object (gwidget);
+  g_return_if_fail (glade_project_has_object (project, object));
+
+  glade_project_model_get_iter_for_object (project, object, &iter);
+  path = gtk_tree_model_get_path (GTK_TREE_MODEL (project), &iter);
+  gtk_tree_model_row_changed (GTK_TREE_MODEL (project), path, &iter);
+  gtk_tree_path_free (path);
 }
 
 /**
- * glade_project_resource_fullpath:
- * @project: The #GladeProject.
- * @resource: The resource basename
+ * glade_project_remove_object:
+ * @project: a #GladeProject
+ * @object: the #GObject to remove
  *
- * Project resource strings may be relative or fullpaths, but glade
- * always expects a copy in the glade file directory, this function
- * is used to make a local path to the file.
+ * Removes @object from @project.
  *
- * Returns: A newly allocated string holding the 
- *          local path the the project resource.
+ * Note that when removing the #GObject from the project we
+ * don't change ->project in the associated #GladeWidget; this
+ * way UNDO can work.
  */
-gchar *
-glade_project_resource_fullpath (GladeProject *project, const gchar *resource)
+void
+glade_project_remove_object (GladeProject *project, GObject *object)
 {
-  gchar *fullpath, *project_dir = NULL, *basename;
+  GladeWidget *gwidget;
+  GList *list, *children;
+  gchar *preview_pid;
 
-  g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
+  g_return_if_fail (GLADE_IS_PROJECT (project));
+  g_return_if_fail (G_IS_OBJECT (object));
 
-  basename = g_path_get_basename (resource);
+  if (!glade_project_has_object (project, object))
+    return;
 
-  if (project->priv->path == NULL)
-    project_dir = g_get_current_dir ();
-  else
-    project_dir = g_path_get_dirname (project->priv->path);
+  if (GLADE_IS_PLACEHOLDER (object))
+    return;
 
-  if (project->priv->resource_path)
+  if ((gwidget = glade_widget_get_from_gobject (object)) == NULL)
+    return;
+
+  /* Recurse and remove deepest children first */
+  if ((children = glade_widget_get_children (gwidget)) != NULL)
     {
-      if (g_path_is_absolute (project->priv->resource_path))
-        fullpath =
-            g_build_filename (project->priv->resource_path, basename, NULL);
-      else
-        fullpath =
-            g_build_filename (project_dir, project->priv->resource_path,
-                              basename, NULL);
+      for (list = children; list && list->data; list = list->next)
+        glade_project_remove_object (project, G_OBJECT (list->data));
+      g_list_free (children);
     }
-  else
-    fullpath = g_build_filename (project_dir, basename, NULL);
 
-  g_free (project_dir);
-  g_free (basename);
+  /* Notify views that the row is being deleted *before* deleting it */
+  glade_project_notify_row_deleted (project, gwidget);
 
-  return fullpath;
+  /* Remove selection and release name from the name context */
+  glade_project_selection_remove (project, object, TRUE);
+  glade_project_release_widget_name (project, gwidget,
+                                     glade_widget_get_name (gwidget));
+
+  g_signal_emit (G_OBJECT (project),
+                 glade_project_signals[REMOVE_WIDGET], 0, gwidget);
+
+  /* Update internal data structure (remove from lists) */
+  project->priv->tree = g_list_remove (project->priv->tree, object);
+  project->priv->objects = g_list_remove (project->priv->objects, object);
+
+  if ((preview_pid = g_object_get_data (G_OBJECT (gwidget), "preview")))
+    g_hash_table_remove (project->priv->previews, preview_pid);
+  
+  /* Unset the project pointer on the GladeWidget */
+  glade_widget_set_project (gwidget, NULL);
+  glade_widget_set_in_project (gwidget, FALSE);
+
+  glade_project_notify_row_has_child (project, gwidget, FALSE);
+  g_object_unref (gwidget);
 }
 
+/*******************************************************************
+ *                          Other API                              *
+ *******************************************************************/
 /**
- * glade_project_widget_visibility_changed:
- * @project: The #GladeProject.
- * @widget: The widget which visibility changed
- * @visible: widget visibility value
+ * glade_project_set_modified:
+ * @project: a #GladeProject
+ * @modified: Whether the project should be set as modified or not
+ * @modification: The first #GladeCommand which caused the project to have unsaved changes
  *
- * Emmits  GladeProject::widget-visibility-changed signal
+ * Set's whether a #GladeProject should be flagged as modified or not. This is useful
+ * for indicating that a project has unsaved changes. If @modified is #TRUE, then
+ * @modification will be recorded as the first change which caused the project to 
+ * have unsaved changes. @modified is #FALSE then @modification will be ignored.
+ *
+ * If @project is already flagged as modified, then calling this method with
+ * @modified as #TRUE, will have no effect. Likewise, if @project is unmodified
+ * then calling this method with @modified as #FALSE, will have no effect.
  *
  */
-void
-glade_project_widget_visibility_changed (GladeProject  *project,
-                                         GladeWidget   *widget,
-                                         gboolean       visible)
+static void
+glade_project_set_modified (GladeProject *project, gboolean modified)
 {
-  g_return_if_fail (GLADE_IS_PROJECT (project));
-  g_return_if_fail (project == glade_widget_get_project (widget));
+  GladeProjectPrivate *priv;
 
-  g_signal_emit (project, glade_project_signals[WIDGET_VISIBILITY_CHANGED], 0,
-                 widget, visible);
-}
+  g_return_if_fail (GLADE_IS_PROJECT (project));
 
-const gchar *
-glade_project_get_path (GladeProject *project)
-{
-  g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
+  priv = project->priv;
 
-  return project->priv->path;
-}
+  if (priv->modified != modified)
+    {
+      priv->modified = !priv->modified;
 
-gchar *
-glade_project_get_name (GladeProject *project)
-{
-  g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
+      if (!priv->modified)
+        {
+          priv->first_modification = project->priv->prev_redo_item;
+          priv->first_modification_is_na = FALSE;
+        }
 
-  if (project->priv->path)
-    return g_filename_display_basename (project->priv->path);
-  else
-    return g_strdup_printf (_("Unsaved %i"), project->priv->unsaved_number);
+      g_object_notify_by_pspec (G_OBJECT (project), glade_project_props[PROP_MODIFIED]);
+    }
 }
 
 /**
- * glade_project_is_loading:
- * @project: A #GladeProject
+ * glade_project_get_modified:
+ * @project: a #GladeProject
  *
- * Returns: Whether the project is being loaded or not
- *       
+ * Get's whether the project has been modified since it was last saved.
+ *
+ * Returns: %TRUE if the project has been modified since it was last saved
  */
 gboolean
-glade_project_is_loading (GladeProject *project)
+glade_project_get_modified (GladeProject *project)
 {
   g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
 
-  return project->priv->loading;
+  return project->priv->modified;
 }
 
-time_t
-glade_project_get_file_mtime (GladeProject *project)
+void
+glade_project_set_pointer_mode (GladeProject *project, GladePointerMode mode)
 {
-  g_return_val_if_fail (GLADE_IS_PROJECT (project), 0);
-
-  return project->priv->mtime;
-}
+  g_return_if_fail (GLADE_IS_PROJECT (project));
 
-/**
- * glade_projects_get_objects:
- * @project: a GladeProject
- *
- * Returns: List of all objects in this project
- */
-const GList *
-glade_project_get_objects (GladeProject *project)
-{
-  g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
+  if (project->priv->pointer_mode != mode)
+    {
+      project->priv->pointer_mode = mode;
 
-  return project->priv->objects;
+      g_object_notify_by_pspec (G_OBJECT (project), glade_project_props[PROP_POINTER_MODE]);
+    }
 }
 
-static void
-target_button_clicked (GtkWidget *widget, GladeProject *project)
+GladePointerMode
+glade_project_get_pointer_mode (GladeProject *project)
 {
-  GladeTargetableVersion *version =
-      g_object_get_data (G_OBJECT (widget), "version");
-  gchar *catalog = g_object_get_data (G_OBJECT (widget), "catalog");
+  g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
 
-  glade_command_set_project_target (project, catalog, version->major, version->minor);
+  return project->priv->pointer_mode;
 }
 
-static void
-verify_clicked (GtkWidget *button, GladeProject *project)
+void
+glade_project_set_template (GladeProject       *project,
+                           GladeWidget        *widget)
 {
-  if (glade_project_verify (project, FALSE,
-                           GLADE_VERIFY_VERSIONS     |
-                           GLADE_VERIFY_DEPRECATIONS |
-                           GLADE_VERIFY_UNRECOGNIZED))
+  g_return_if_fail (GLADE_IS_PROJECT (project));
+  g_return_if_fail (widget == NULL || GLADE_IS_WIDGET (widget));
+
+  if (widget)
     {
-      gchar *name = glade_project_get_name (project);
-      glade_util_ui_message (glade_app_get_window (),
-                             GLADE_UI_INFO, NULL,
-                             _("Project %s has no deprecated widgets "
-                               "or version mismatches."), name);
-      g_free (name);
-    }
-}
+      GObject *object = glade_widget_get_object (widget);
 
-static void
-resource_default_toggled (GtkWidget *widget, GladeProject *project)
-{
-  if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
-    return;
+      g_return_if_fail (GTK_IS_WIDGET (object));
+      g_return_if_fail (glade_widget_get_parent (widget) == NULL);
+      g_return_if_fail (glade_widget_get_project (widget) == project);
+    }
 
-  glade_project_set_resource_path (project, NULL);
-  gtk_widget_set_sensitive (project->priv->relative_path_entry, FALSE);
-  gtk_widget_set_sensitive (project->priv->full_path_button, FALSE);
-}
+  /* Let's not add any strong reference here, we already own the widget */
+  if (project->priv->template != widget)
+    {
+      if (project->priv->template)
+       glade_widget_set_is_composite (project->priv->template, FALSE);
 
+      project->priv->template = widget;
 
-static void
-resource_relative_toggled (GtkWidget *widget, GladeProject *project)
-{
-  if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
-    return;
+      if (project->priv->template)
+       glade_widget_set_is_composite (project->priv->template, TRUE);
 
-  gtk_widget_set_sensitive (project->priv->relative_path_entry, TRUE);
-  gtk_widget_set_sensitive (project->priv->full_path_button, FALSE);
+      g_object_notify_by_pspec (G_OBJECT (project), glade_project_props[PROP_TEMPLATE]);
+    }
 }
 
-static void
-resource_fullpath_toggled (GtkWidget *widget, GladeProject *project)
+GladeWidget *
+glade_project_get_template (GladeProject       *project)
 {
-  if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
-    return;
+  g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
 
-  gtk_widget_set_sensitive (project->priv->relative_path_entry, FALSE);
-  gtk_widget_set_sensitive (project->priv->full_path_button, TRUE);
+  return project->priv->template;
 }
 
-static void
-resource_path_activated (GtkEntry *entry, GladeProject *project)
+void
+glade_project_set_add_item (GladeProject *project, GladeWidgetAdaptor *adaptor)
 {
-  const gchar *text = gtk_entry_get_text (entry);
+  GladeProjectPrivate *priv;
 
-  glade_project_set_resource_path (project, text ? g_strdup (text) : NULL);
-}
+  g_return_if_fail (GLADE_IS_PROJECT (project));
 
+  priv = project->priv;
 
-static void
-resource_full_path_set (GtkFileChooserButton *button, GladeProject *project)
-{
-  gchar *text = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (button));
+  if (priv->add_item != adaptor)
+    {
+      priv->add_item = adaptor;
 
-  glade_project_set_resource_path (project, text);
+      g_object_notify_by_pspec (G_OBJECT (project), glade_project_props[PROP_ADD_ITEM]);
+    }
 }
 
-static void
-update_prefs_for_resource_path (GladeProject *project)
+GladeWidgetAdaptor *
+glade_project_get_add_item (GladeProject *project)
 {
-  GladeProjectPrivate *priv = project->priv;
-  
-  gtk_widget_set_sensitive (priv->full_path_button, FALSE);
-  gtk_widget_set_sensitive (priv->relative_path_entry, FALSE);
-
-
-  g_signal_handlers_block_by_func (priv->resource_default_radio,
-                                   G_CALLBACK (resource_default_toggled),
-                                   project);
-  g_signal_handlers_block_by_func (priv->resource_relative_radio,
-                                   G_CALLBACK (resource_relative_toggled),
-                                   project);
-  g_signal_handlers_block_by_func (priv->resource_fullpath_radio,
-                                   G_CALLBACK (resource_fullpath_toggled),
-                                   project);
-  g_signal_handlers_block_by_func (priv->relative_path_entry,
-                                   G_CALLBACK (resource_path_activated),
-                                   project);
-
-  if (project->priv->resource_path == NULL)
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->resource_default_radio), TRUE);
-  else if (g_path_is_absolute (priv->resource_path))
-    {
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->resource_fullpath_radio), TRUE);
-      gtk_widget_set_sensitive (priv->full_path_button, TRUE);
-    }
-  else
-    {
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->resource_relative_radio), TRUE);
-      gtk_widget_set_sensitive (priv->relative_path_entry, TRUE);
-    }
-
-  gtk_entry_set_text (GTK_ENTRY (priv->relative_path_entry),
-                      priv->resource_path ? priv->resource_path : "");
+  g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
 
-  g_signal_handlers_unblock_by_func (priv->resource_default_radio,
-                                     G_CALLBACK (resource_default_toggled),
-                                     project);
-  g_signal_handlers_unblock_by_func (priv->resource_relative_radio,
-                                     G_CALLBACK (resource_relative_toggled),
-                                     project);
-  g_signal_handlers_unblock_by_func (priv->resource_fullpath_radio,
-                                     G_CALLBACK (resource_fullpath_toggled),
-                                     project);
-  g_signal_handlers_unblock_by_func (priv->relative_path_entry,
-                                     G_CALLBACK (resource_path_activated),
-                                     project);
+  return project->priv->add_item;
 }
 
-static void
-glade_project_target_version_box_fill (GladeProject *project, GtkWidget *vbox)
+void
+glade_project_set_target_version (GladeProject *project,
+                                  const gchar *catalog,
+                                  gint major,
+                                  gint minor)
 {
-  GtkWidget *label, *active_radio, *target_radio, *hbox;
-  GList *list, *targets;
-
-  /* Add stuff to vbox */
-  for (list = glade_app_get_catalogs (); list; list = g_list_next (list))
-    {
-      GladeCatalog *catalog = list->data;
-      gint minor, major;
-
-      /* Skip if theres only one option */
-      if (g_list_length (glade_catalog_get_targets (catalog)) <= 1)
-        continue;
-
-      glade_project_get_target_version (project,
-                                        glade_catalog_get_name (catalog),
-                                        &major, &minor);
+  g_return_if_fail (GLADE_IS_PROJECT (project));
+  g_return_if_fail (catalog && catalog[0]);
+  g_return_if_fail (major >= 0);
+  g_return_if_fail (minor >= 0);
 
-      /* Special case to mark GTK+ in upper case */
-      if (strcmp (glade_catalog_get_name (catalog), "gtk+") == 0)
-        label = gtk_label_new ("GTK+");
-      else
-        label = gtk_label_new (glade_catalog_get_name (catalog));
-      gtk_misc_set_alignment (GTK_MISC (label), 0.0F, 0.5F);
+  g_hash_table_insert (project->priv->target_versions_major,
+                       g_strdup (catalog), GINT_TO_POINTER ((int) major));
+  g_hash_table_insert (project->priv->target_versions_minor,
+                       g_strdup (catalog), GINT_TO_POINTER ((int) minor));
 
-      gtk_widget_show (label);
-      gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 2);
-      hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+  glade_project_verify_project_for_ui (project);
 
-      active_radio = target_radio = NULL;
+  g_signal_emit (project, glade_project_signals[TARGETS_CHANGED], 0);
+}
 
-      for (targets = glade_catalog_get_targets (catalog);
-           targets; targets = targets->next)
-        {
-          GladeTargetableVersion *version = targets->data;
-          gchar *name = g_strdup_printf ("%d.%d",
-                                         version->major,
-                                         version->minor);
+static void
+glade_project_set_readonly (GladeProject *project, gboolean readonly)
+{
+  g_assert (GLADE_IS_PROJECT (project));
 
-          if (!target_radio)
-            target_radio = gtk_radio_button_new_with_label (NULL, name);
-          else
-            target_radio =
-                gtk_radio_button_new_with_label_from_widget
-                (GTK_RADIO_BUTTON (target_radio), name);
-          g_free (name);
+  if (project->priv->readonly != readonly)
+    {
+      project->priv->readonly = readonly;
+      g_object_notify_by_pspec (G_OBJECT (project), glade_project_props[PROP_READ_ONLY]);
+    }
+}
 
-          g_signal_connect (G_OBJECT (target_radio), "clicked",
-                            G_CALLBACK (target_button_clicked), project);
+/**
+ * glade_project_get_target_version:
+ * @project: a #GladeProject
+ * @catalog: the name of the catalog @project includes
+ * @major: the return location for the target major version
+ * @minor: the return location for the target minor version
+ *
+ * Fetches the target version of the @project for @catalog.
+ *
+ */
+void
+glade_project_get_target_version (GladeProject *project,
+                                  const gchar *catalog,
+                                  gint *major,
+                                  gint *minor)
+{
+  g_return_if_fail (GLADE_IS_PROJECT (project));
+  g_return_if_fail (catalog && catalog[0]);
+  g_return_if_fail (major && minor);
 
-          g_object_set_data (G_OBJECT (target_radio), "version", version);
-          g_object_set_data (G_OBJECT (target_radio), "catalog",
-                             (gchar *) glade_catalog_get_name (catalog));
+  *major = GPOINTER_TO_INT
+      (g_hash_table_lookup (project->priv->target_versions_major, catalog));
+  *minor = GPOINTER_TO_INT
+      (g_hash_table_lookup (project->priv->target_versions_minor, catalog));
+}
 
-          gtk_widget_show (target_radio);
-          gtk_box_pack_end (GTK_BOX (hbox), target_radio, TRUE, TRUE, 2);
+/**
+ * glade_project_get_readonly:
+ * @project: a #GladeProject
+ *
+ * Gets whether the project is read only or not
+ *
+ * Returns: TRUE if project is read only
+ */
+gboolean
+glade_project_get_readonly (GladeProject *project)
+{
+  g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
 
-          if (major == version->major && minor == version->minor)
-            active_radio = target_radio;
+  return project->priv->readonly;
+}
 
-        }
+/**
+ * glade_project_selection_changed:
+ * @project: a #GladeProject
+ *
+ * Causes @project to emit a "selection_changed" signal.
+ */
+void
+glade_project_selection_changed (GladeProject *project)
+{
+  g_return_if_fail (GLADE_IS_PROJECT (project));
 
-      if (active_radio)
-        {
-          gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (active_radio), TRUE);
-          g_hash_table_insert (project->priv->target_radios,
-                               g_strdup (glade_catalog_get_name (catalog)),
-                               gtk_radio_button_get_group (GTK_RADIO_BUTTON
-                                                           (active_radio)));
-        }
-      else
-        g_warning ("Corrupt catalog versions");
+  g_signal_emit (G_OBJECT (project),
+                 glade_project_signals[SELECTION_CHANGED], 0);
 
-      gtk_widget_show (hbox);
-      gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 2);
-    }
+  /* Cancel any idle we have */
+  if (project->priv->selection_changed_id > 0)
+    project->priv->selection_changed_id = 
+      (g_source_remove (project->priv->selection_changed_id), 0);
 }
 
-static void
-on_domain_entry_changed (GtkWidget *entry, GladeProject *project)
+static gboolean
+selection_change_idle (GladeProject *project)
 {
-  glade_command_set_project_domain (project, gtk_entry_get_text (GTK_ENTRY (entry)));
+  project->priv->selection_changed_id = 0;
+  glade_project_selection_changed (project);
+  return FALSE;
 }
 
-static void
-on_template_combo_box_changed (GtkComboBox *combo, GladeProject *project)
+void
+glade_project_queue_selection_changed (GladeProject *project)
 {
-  GtkTreeIter iter;
-
-  if (project->priv->loading)
-    return;
-
-  if (gtk_combo_box_get_active_iter (combo, &iter))
-    {
-      GladeWidget *gwidget;
-      GObject *object;
-
-      gtk_tree_model_get (gtk_combo_box_get_model (combo), &iter,
-                          GLADE_PROJECT_MODEL_COLUMN_OBJECT, &object, -1);
-      
-      gwidget = glade_widget_get_from_gobject (object);
+  g_return_if_fail (GLADE_IS_PROJECT (project));
 
-      glade_command_set_project_template (project, gwidget);
-    }
+  if (project->priv->selection_changed_id == 0)
+    project->priv->selection_changed_id = 
+      g_idle_add ((GSourceFunc) selection_change_idle, project);
 }
 
 static void
-on_template_checkbutton_toggled (GtkToggleButton *togglebutton,
-                                 GladeProject    *project)
+glade_project_set_has_selection (GladeProject *project, gboolean has_selection)
 {
-  gboolean active = gtk_toggle_button_get_active (togglebutton);
-  gboolean composite = FALSE;
+  g_assert (GLADE_IS_PROJECT (project));
 
-  if (project->priv->loading)
-    return;
-  
-  if (active)
+  if (project->priv->has_selection != has_selection)
     {
-      GList *l;
-
-      for (l = project->priv->tree; l; l = l->next)
-       {
-         GObject *object = l->data;
-         GladeWidget *gwidget;
-
-         gwidget = glade_widget_get_from_gobject (object);
-
-         if (GTK_IS_WIDGET (object))
-           {
-             glade_command_set_project_template (project, gwidget);
-             composite = TRUE;
-             break;
-           }
-       }
-
-      if (!composite)
-       gtk_toggle_button_set_active (togglebutton, FALSE);
+      project->priv->has_selection = has_selection;
+      g_object_notify_by_pspec (G_OBJECT (project), glade_project_props[PROP_HAS_SELECTION]);
     }
-  else
-    glade_command_set_project_template (project, NULL);
 }
 
-static gboolean
-template_visible_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
+/**
+ * glade_project_get_has_selection:
+ * @project: a #GladeProject
+ *
+ * Returns: whether @project currently has a selection
+ */
+gboolean
+glade_project_get_has_selection (GladeProject *project)
 {
-  GtkTreeIter parent;
-  gboolean visible;
-  GObject *object;
-
-  visible = !gtk_tree_model_iter_parent (model, &parent, iter);
-
-  if (visible)
-    {
-      gtk_tree_model_get (model, iter,
-                         GLADE_PROJECT_MODEL_COLUMN_OBJECT, &object,
-                         -1);
-
-      visible = GTK_IS_WIDGET (object);
-      g_object_unref (object);
-    }
+  g_assert (GLADE_IS_PROJECT (project));
 
-  return visible;
+  return project->priv->has_selection;
 }
 
-static GtkTreeModel *
-glade_project_toplevel_model_filter_new (GladeProject *project)
+/**
+ * glade_project_is_selected:
+ * @project: a #GladeProject
+ * @object: a #GObject
+ *
+ * Returns: whether @object is in @project selection
+ */
+gboolean
+glade_project_is_selected (GladeProject *project, GObject *object)
 {
-  GtkTreeModel *model = gtk_tree_model_filter_new (GTK_TREE_MODEL (project), NULL);
-  gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (model),
-                                          template_visible_func, NULL, NULL);
-  return model;
+  g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
+  return (g_list_find (project->priv->selection, object)) != NULL;
 }
 
-static void
-glade_project_fix_template (GladeProject *project)
+/**
+ * glade_project_selection_clear:
+ * @project: a #GladeProject
+ * @emit_signal: whether or not to emit a signal indication a selection change
+ *
+ * Clears @project's selection chain
+ *
+ * If @emit_signal is %TRUE, calls glade_project_selection_changed().
+ */
+void
+glade_project_selection_clear (GladeProject *project, gboolean emit_signal)
 {
-  GtkTreeModel *model;
-  GladeProjectPrivate *priv = project->priv;
-  GtkTreeIter iter;
-  gboolean valid;
-  gboolean composite = FALSE;
-
-  g_signal_handlers_block_by_func (priv->template_combobox, on_template_combo_box_changed, project);
-  g_signal_handlers_block_by_func (priv->template_checkbutton, on_template_checkbutton_toggled, project);
+  GList *l;
 
-  model = gtk_combo_box_get_model (GTK_COMBO_BOX (priv->template_combobox));
-  if (!model)
-    {
-      model = glade_project_toplevel_model_filter_new (project);
+  g_return_if_fail (GLADE_IS_PROJECT (project));
 
-      gtk_combo_box_set_model (GTK_COMBO_BOX (priv->template_combobox), model);
-      g_object_unref (model);
-    }
+  if (project->priv->selection == NULL)
+    return;
 
-  valid = gtk_tree_model_get_iter_first (model, &iter);
-  while (valid)
+  for (l = project->priv->selection; l; l = l->next)
     {
-      GladeWidget *gwidget;
-      GObject *obj;
-      
-      gtk_tree_model_get (model, &iter,
-                          GLADE_PROJECT_MODEL_COLUMN_OBJECT, &obj,
-                          -1);
-
-      gwidget = glade_widget_get_from_gobject (obj);
-      g_object_unref (obj);
-
-      composite = glade_widget_get_is_composite (gwidget);
-
-      if (composite)
-        {
-          gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->template_combobox), &iter);
-
-         /* Resolve the template widget for this project */
-         priv->template = gwidget;
-
-         break;
-        }
-
-      valid = gtk_tree_model_iter_next (model, &iter);
+      if (GTK_IS_WIDGET (l->data))
+        gtk_widget_queue_draw (GTK_WIDGET (l->data));
     }
 
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->template_checkbutton), composite);
-  gtk_widget_set_sensitive (priv->template_combobox, composite);
-
-  if (!composite && gtk_combo_box_get_model (GTK_COMBO_BOX (priv->template_combobox)))
-    gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->template_combobox), NULL);
+  g_list_free (project->priv->selection);
+  project->priv->selection = NULL;
+  glade_project_set_has_selection (project, FALSE);
 
-  g_signal_handlers_unblock_by_func (priv->template_combobox, on_template_combo_box_changed, project);
-  g_signal_handlers_unblock_by_func (priv->template_checkbutton, on_template_checkbutton_toggled, project);
+  if (emit_signal)
+    glade_project_selection_changed (project);
 }
 
-#define GET_OBJECT(b,c,o) c(gtk_builder_get_object(b,o));
-
-static GtkWidget *
-glade_project_build_prefs_dialog (GladeProject *project)
+/**
+ * glade_project_selection_remove:
+ * @project: a #GladeProject
+ * @object:  a #GObject in @project
+ * @emit_signal: whether or not to emit a signal 
+ *               indicating a selection change
+ *
+ * Removes @object from the selection chain of @project
+ *
+ * If @emit_signal is %TRUE, calls glade_project_selection_changed().
+ */
+void
+glade_project_selection_remove (GladeProject *project,
+                                GObject *object,
+                                gboolean emit_signal)
 {
-  GladeProjectPrivate *priv = project->priv;  
-  GtkWidget *verify_button, *toolkit_box;
-  GError *error = NULL;
-  GtkBuilder *builder;
-  GtkWidget *dialog;
+  g_return_if_fail (GLADE_IS_PROJECT (project));
+  g_return_if_fail (G_IS_OBJECT (object));
 
-  /* Build UI */
-  builder = gtk_builder_new ();
-  if (gtk_builder_add_from_resource (builder, "/org/gnome/gladeui/glade-project-properties.ui", &error) == 0)
+  if (glade_project_is_selected (project, object))
     {
-      g_warning ("gtk_builder_add_from_resource() failed %s", (error) ? error->message : "");
-      return NULL;
+      project->priv->selection =
+          g_list_remove (project->priv->selection, object);
+      if (project->priv->selection == NULL)
+        glade_project_set_has_selection (project, FALSE);
+      if (emit_signal)
+        glade_project_selection_changed (project);
     }
+}
 
-  /* Fetch Pointers */
-  dialog = GET_OBJECT (builder, GTK_WIDGET, "prefs_dialog");
-  g_object_ref_sink (dialog);
-  priv->resource_default_radio = GET_OBJECT (builder, GTK_WIDGET, "resource_default_radio");
-  priv->resource_relative_radio = GET_OBJECT (builder, GTK_WIDGET, "resource_relative_radio");
-  priv->resource_fullpath_radio = GET_OBJECT (builder, GTK_WIDGET, "resource_fullpath_radio");
-  priv->relative_path_entry = GET_OBJECT (builder, GTK_WIDGET, "relative_path_entry");
-  priv->full_path_button = GET_OBJECT (builder, GTK_WIDGET, "full_path_button");
-  priv->domain_entry = GET_OBJECT (builder, GTK_WIDGET, "domain_entry");
-  priv->template_checkbutton = GET_OBJECT (builder, GTK_WIDGET, "template_checkbutton");
-  priv->template_combobox = GET_OBJECT (builder, GTK_WIDGET, "template_combobox");
-  g_signal_connect (priv->template_combobox, "changed",
-                    G_CALLBACK (on_template_combo_box_changed), project);
-  g_signal_connect (priv->template_checkbutton, "toggled",
-                    G_CALLBACK (on_template_checkbutton_toggled), project);
-
-  verify_button = GET_OBJECT (builder, GTK_WIDGET, "verify_button");
-  toolkit_box = GET_OBJECT (builder, GTK_WIDGET, "toolkit_box");
-  glade_project_target_version_box_fill (project, toolkit_box);
-
-  update_prefs_for_resource_path (project);
-
-  g_signal_connect (priv->resource_default_radio, "toggled",
-                    G_CALLBACK (resource_default_toggled), project);
-  g_signal_connect (priv->resource_relative_radio, "toggled",
-                    G_CALLBACK (resource_relative_toggled), project);
-  g_signal_connect (priv->resource_fullpath_radio, "toggled",
-                    G_CALLBACK (resource_fullpath_toggled), project);
+/**
+ * glade_project_selection_add:
+ * @project: a #GladeProject
+ * @object:  a #GObject in @project
+ * @emit_signal: whether or not to emit a signal indicating 
+ *               a selection change
+ *
+ * Adds @object to the selection chain of @project
+ *
+ * If @emit_signal is %TRUE, calls glade_project_selection_changed().
+ */
+void
+glade_project_selection_add (GladeProject *project,
+                             GObject *object,
+                             gboolean emit_signal)
+{
+  g_return_if_fail (GLADE_IS_PROJECT (project));
+  g_return_if_fail (G_IS_OBJECT (object));
+  g_return_if_fail (glade_project_has_object (project, object));
 
-  g_signal_connect (priv->relative_path_entry, "activate",
-                    G_CALLBACK (resource_path_activated), project);
-  g_signal_connect (priv->full_path_button, "file-set",
-                    G_CALLBACK (resource_full_path_set), project);
+  if (glade_project_is_selected (project, object) == FALSE)
+    {
+      gboolean toggle_has_selection = (project->priv->selection == NULL);
 
-  g_signal_connect (verify_button, "clicked",
-                    G_CALLBACK (verify_clicked), project);
+      if (GTK_IS_WIDGET (object))
+        gtk_widget_queue_draw (GTK_WIDGET (object));
 
-  g_signal_connect (priv->domain_entry, "changed",
-                    G_CALLBACK (on_domain_entry_changed), project);
+      project->priv->selection =
+        g_list_prepend (project->priv->selection, object);
 
-  gtk_builder_connect_signals (builder, NULL);
-  g_object_unref (builder);
+      if (toggle_has_selection)
+        glade_project_set_has_selection (project, TRUE);
 
-  return dialog;
+      if (emit_signal)
+        glade_project_selection_changed (project);
+    }
 }
 
 /**
- * glade_project_properties:
- * @project: A #GladeProject
+ * glade_project_selection_set:
+ * @project: a #GladeProject
+ * @object:  a #GObject in @project
+ * @emit_signal: whether or not to emit a signal 
+ *               indicating a selection change
  *
- * Runs a document properties dialog for @project.
+ * Set the selection in @project to @object
+ *
+ * If @emit_signal is %TRUE, calls glade_project_selection_changed().
  */
 void
-glade_project_properties (GladeProject *project)
+glade_project_selection_set (GladeProject *project,
+                             GObject *object,
+                             gboolean emit_signal)
 {
   g_return_if_fail (GLADE_IS_PROJECT (project));
+  g_return_if_fail (G_IS_OBJECT (object));
+  g_return_if_fail (glade_project_has_object (project, object));
 
-  gtk_window_present (GTK_WINDOW (project->priv->prefs_dialog));
+  if (glade_project_is_selected (project, object) == FALSE ||
+      g_list_length (project->priv->selection) != 1)
+    {
+      glade_project_selection_clear (project, FALSE);
+      glade_project_selection_add (project, object, emit_signal);
+    }
 }
 
-
-gchar *
-glade_project_display_dependencies (GladeProject *project)
+/**
+ * glade_project_selection_get:
+ * @project: a #GladeProject
+ *
+ * Returns: a #GList containing the #GtkWidget items currently selected in @project
+ */
+GList *
+glade_project_selection_get (GladeProject *project)
 {
-  GList *catalogs, *l;
-  GString *string;
-
   g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
 
-  string = g_string_new ("");
+  return project->priv->selection;
+}
 
-  catalogs = glade_project_required_libs (project);
-  for (l = catalogs; l; l = l->next)
+/**
+ * glade_project_required_libs:
+ * @project: a #GladeProject
+ *
+ * Returns: a #GList of allocated strings which are the names
+ * of the required catalogs for this project
+ */
+GList *
+glade_project_required_libs (GladeProject *project)
+{
+  GList *required = NULL, *l, *ll;
+  GladeWidget *gwidget;
+  gboolean listed;
+
+  for (l = project->priv->objects; l; l = l->next)
     {
-      gchar *catalog = l->data;
-      gint major = 0, minor = 0;
+      gchar *catalog = NULL;
 
-      glade_project_get_target_version (project, catalog, &major, &minor);
+      gwidget = glade_widget_get_from_gobject (l->data);
+      g_assert (gwidget);
 
-      if (l != catalogs)
-        g_string_append (string, ", ");
+      g_object_get (glade_widget_get_adaptor (gwidget), "catalog", &catalog, NULL);
 
-      /* Capitalize GTK+ */
-      if (strcmp (catalog, "gtk+") == 0)
-        g_string_append_printf (string, "GTK+ >= %d.%d", major, minor);
-      else if (major && minor)
-        g_string_append_printf (string, "%s >= %d.%d", catalog, major, minor);
-      else
-        g_string_append_printf (string, "%s", catalog);
+      if (catalog)
+        {
+          listed = FALSE;
+          for (ll = required; ll; ll = ll->next)
+            if (!strcmp ((gchar *) ll->data, catalog))
+              {
+                listed = TRUE;
+                break;
+              }
 
-      g_free (catalog);
+          if (!listed)
+            required = g_list_prepend (required, catalog);
+        }
     }
-  g_list_free (catalogs);
 
-  return g_string_free (string, FALSE);
+  /* Assume GTK+ here */
+  if (!required)
+    required = g_list_prepend (required, g_strdup ("gtk+"));
+
+  required = g_list_reverse (required);
+    
+  for (l = project->priv->unknown_catalogs; l; l = g_list_next (l))
+    {
+      CatalogInfo *data = l->data;
+      /* Keep position to make sure we do not create a diff when saving */
+      required = g_list_insert (required, g_strdup (data->catalog), data->position);
+    }
+  
+  return required;
 }
 
 /**
- * glade_project_toplevels:
+ * glade_project_undo:
  * @project: a #GladeProject
- *
- * Returns: a #GList containing the #GtkWidget toplevel items in @project
+ * 
+ * Undoes a #GladeCommand in this project.
  */
-GList *
-glade_project_toplevels (GladeProject *project)
+void
+glade_project_undo (GladeProject *project)
 {
-  g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
-
-  return project->priv->tree;
+  g_return_if_fail (GLADE_IS_PROJECT (project));
+  GLADE_PROJECT_GET_CLASS (project)->undo (project);
 }
 
 /**
- * glade_project_set_translation_domain:
+ * glade_project_undo:
  * @project: a #GladeProject
- * @domain: the translation domain
- *
- * Set the project translation domain.
+ * 
+ * Redoes a #GladeCommand in this project.
  */
 void
-glade_project_set_translation_domain (GladeProject *project, const gchar *domain)
+glade_project_redo (GladeProject *project)
 {
-  GladeProjectPrivate *priv;
-
   g_return_if_fail (GLADE_IS_PROJECT (project));
-
-  priv = project->priv;
-
-  if (g_strcmp0 (priv->translation_domain, domain))
-    {
-      g_free (priv->translation_domain);
-      priv->translation_domain = g_strdup (domain);
-
-      g_signal_handlers_block_by_func (priv->domain_entry, on_domain_entry_changed, project);
-      gtk_entry_set_text (GTK_ENTRY (priv->domain_entry), domain);
-      g_signal_handlers_unblock_by_func (priv->domain_entry, on_domain_entry_changed, project);
-
-      g_object_notify_by_pspec (G_OBJECT (project),
-                                properties[PROP_TRANSLATION_DOMAIN]);
-    }
+  GLADE_PROJECT_GET_CLASS (project)->redo (project);
 }
 
 /**
- * glade_project_get_translation_domain:
+ * glade_project_next_undo_item:
  * @project: a #GladeProject
+ * 
+ * Gets the next undo item on @project's command stack.
  *
- * Returns: the translation domain
+ * Returns: the #GladeCommand
  */
-const gchar *
-glade_project_get_translation_domain (GladeProject *project)
+GladeCommand *
+glade_project_next_undo_item (GladeProject *project)
 {
   g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
-
-  return project->priv->translation_domain;
+  return GLADE_PROJECT_GET_CLASS (project)->next_undo_item (project);
 }
 
-/* GtkTreeModel implementation */
-
-static GObject *
-glade_project_nth_child (GladeProject *project,
-                         GladeWidget  *parent, 
-                         gint          nth)
+/**
+ * glade_project_next_redo_item:
+ * @project: a #GladeProject
+ * 
+ * Gets the next redo item on @project's command stack.
+ *
+ * Returns: the #GladeCommand
+ */
+GladeCommand *
+glade_project_next_redo_item (GladeProject *project)
 {
-  GList   *children, *list;
-  GObject *child = NULL;
-  gint     i;
-
-  children = glade_widget_get_children (parent);
-
-  for (list = children, i = 0; list; list = list->next)
-    {
-      child = list->data;
-
-      if (!glade_project_has_object (project, child))
-         continue;      
-
-      if (i == nth)
-        break;
-
-      child = NULL;
-      i++;
-    }
-
-  g_list_free (children);
-
-  return child;
+  g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
+  return GLADE_PROJECT_GET_CLASS (project)->next_redo_item (project);
 }
 
-static gint
-glade_project_child_position (GladeProject *project,
-                              GladeWidget  *parent, 
-                              GObject      *child)
+/**
+ * glade_project_push_undo:
+ * @project: a #GladeProject
+ * @cmd: the #GladeCommand
+ * 
+ * Pushes a newly created #GladeCommand onto @projects stack.
+ */
+void
+glade_project_push_undo (GladeProject *project, GladeCommand *cmd)
 {
-  GList   *children, *list;
-  GObject *iter;
-  gint     i, position = -1;
-
-  children = glade_widget_get_children (parent);
-
-  for (list = children, i = 0; list; list = list->next)
-    {
-      iter = list->data;
-
-      if (!glade_project_has_object (project, iter))
-        continue;
-
-      if (iter == child)
-        {
-          position = i;
-          break;
-        }
-      i++;
-    }
-
-  g_list_free (children);
+  g_return_if_fail (GLADE_IS_PROJECT (project));
+  g_return_if_fail (GLADE_IS_COMMAND (cmd));
 
-  return position;
+  GLADE_PROJECT_GET_CLASS (project)->push_undo (project, cmd);
 }
 
-static gint
-glade_project_count_children (GladeProject *project, GladeWidget *parent)
+static GList *
+walk_command (GList *list, gboolean forward)
 {
-  GList   *children, *list;
-  GObject *iter;
-  gint     i;
+  GladeCommand *cmd = list->data;
+  GladeCommand *next_cmd;
 
-  children = glade_widget_get_children (parent);
+  if (forward)
+    list = list->next;
+  else
+    list = list->prev;
 
-  for (list = children, i = 0; list; list = list->next)
+  next_cmd = list ? list->data : NULL;
+
+  while (list && 
+   glade_command_group_id (next_cmd) != 0 && 
+   glade_command_group_id (next_cmd) == glade_command_group_id (cmd))
     {
-      iter = list->data;
+      if (forward)
+        list = list->next;
+      else
+        list = list->prev;
 
-      if (!glade_project_has_object (project, iter))
-        continue;
-      i++;
+      if (list)
+        next_cmd = list->data;
     }
 
-  g_list_free (children);
-
-  return i;
+  return list;
 }
 
 static void
-glade_project_model_get_iter_for_object (GladeProject *project,
-                                         GObject *object,
-                                         GtkTreeIter *iter)
+undo_item_activated (GtkMenuItem *item, GladeProject *project)
 {
-  g_assert (object);
-
-  iter->stamp = project->priv->stamp;
-  iter->user_data = object;
-}
+  gint index, next_index;
 
-static GtkTreeModelFlags
-glade_project_model_get_flags (GtkTreeModel *model)
-{
-  return 0;
-}
+  GladeCommand *cmd = g_object_get_data (G_OBJECT (item), "command-data");
+  GladeCommand *next_cmd;
 
-static gint
-glade_project_model_get_n_columns (GtkTreeModel *model)
-{
-  return GLADE_PROJECT_MODEL_N_COLUMNS;
-}
+  index = g_list_index (project->priv->undo_stack, cmd);
 
-static GType
-glade_project_model_get_column_type (GtkTreeModel *model, gint column)
-{
-  switch (column)
+  do
     {
-      case GLADE_PROJECT_MODEL_COLUMN_ICON_NAME:
-        return G_TYPE_STRING;
-      case GLADE_PROJECT_MODEL_COLUMN_NAME:
-        return G_TYPE_STRING;
-      case GLADE_PROJECT_MODEL_COLUMN_TYPE_NAME:
-        return G_TYPE_STRING;
-      case GLADE_PROJECT_MODEL_COLUMN_OBJECT:
-        return G_TYPE_OBJECT;
-      case GLADE_PROJECT_MODEL_COLUMN_MISC:
-        return G_TYPE_STRING;
-      case GLADE_PROJECT_MODEL_COLUMN_WARNING:
-        return G_TYPE_STRING;
-      default:
-        g_assert_not_reached ();
-        return G_TYPE_NONE;
-    }
-}
-
-static gboolean
-glade_project_model_get_iter (GtkTreeModel *model,
-                              GtkTreeIter *iter,
-                              GtkTreePath *path)
-{
-  GladeProject *project = GLADE_PROJECT (model);
-  gint         *indices = gtk_tree_path_get_indices (path);
-  gint          depth = gtk_tree_path_get_depth (path);
-  GladeWidget  *widget;
-  GObject      *object;
-  gint          i;
-  GList        *parent;
+      next_cmd = glade_project_next_undo_item (project);
+      next_index = g_list_index (project->priv->undo_stack, next_cmd);
+
+      glade_project_undo (project);
 
-  if ((parent = g_list_nth (project->priv->tree, indices[0])) != NULL)
-    {
-      object = parent->data;
-      widget = glade_widget_get_from_gobject (object);
-    }
-  else
-    {
-      iter->stamp = 0;
-      iter->user_data = NULL;
-      return FALSE;
     }
+  while (next_index > index);
+}
 
-  for (i = 1; i < depth; i++)
-    {
-      object = glade_project_nth_child (project, widget, indices[i]);
+static void
+redo_item_activated (GtkMenuItem *item, GladeProject *project)
+{
+  gint index, next_index;
 
-      if (!object)
-        {
-          iter->stamp = 0;
-          iter->user_data = NULL;
-          return FALSE;
-        }
+  GladeCommand *cmd = g_object_get_data (G_OBJECT (item), "command-data");
+  GladeCommand *next_cmd;
 
-      widget = glade_widget_get_from_gobject (object);
-    }
+  index = g_list_index (project->priv->undo_stack, cmd);
 
-  if (object)
-    {
-      glade_project_model_get_iter_for_object (project, object, iter);
-      return TRUE;
-    }
-  else
+  do
     {
-      iter->stamp = 0;
-      iter->user_data = NULL;
-      return FALSE;
+      next_cmd = glade_project_next_redo_item (project);
+      next_index = g_list_index (project->priv->undo_stack, next_cmd);
+
+      glade_project_redo (project);
+
     }
+  while (next_index < index);
 }
 
-static GtkTreePath *
-glade_project_model_get_path (GtkTreeModel *model, GtkTreeIter *iter)
+
+/**
+ * glade_project_undo_items:
+ * @project: A #GladeProject
+ *
+ * Creates a menu of the undo items in the project stack
+ *
+ * Returns: A newly created menu
+ */
+GtkWidget *
+glade_project_undo_items (GladeProject *project)
 {
-  GladeProject *project = GLADE_PROJECT (model);
-  GtkTreePath  *path;
-  GObject      *object;
-  GladeWidget  *widget;
-  GladeWidget  *toplevel;
-  GladeWidget  *parent;
-  GList        *top;
+  GtkWidget *menu = NULL;
+  GtkWidget *item;
+  GladeCommand *cmd;
+  GList *l;
 
-  g_return_val_if_fail (VALID_ITER (project, iter), NULL);
+  g_return_val_if_fail (project != NULL, NULL);
 
-  object   = iter->user_data;
-  widget   = glade_widget_get_from_gobject (object);
-  toplevel = glade_widget_get_toplevel (widget);
-  parent   = widget;
+  for (l = project->priv->prev_redo_item; l; l = walk_command (l, FALSE))
+    {
+      cmd = l->data;
 
-  path = gtk_tree_path_new ();
+      if (!menu)
+        menu = gtk_menu_new ();
 
-  while ((parent = glade_widget_get_parent (widget)) != NULL)
-    {
-      gint position;
+      item = gtk_menu_item_new_with_label (glade_command_description (cmd));
+      gtk_widget_show (item);
+      gtk_menu_shell_append (GTK_MENU_SHELL (menu), GTK_WIDGET (item));
+      g_object_set_data (G_OBJECT (item), "command-data", cmd);
 
-      if ((position = glade_project_child_position (project, parent, 
-                                                    glade_widget_get_object (widget))) < 0)
-        gtk_tree_path_prepend_index (path, 0);
-      else
-        gtk_tree_path_prepend_index (path, position);
+      g_signal_connect (G_OBJECT (item), "activate",
+                        G_CALLBACK (undo_item_activated), project);
 
-      widget = parent;
     }
 
-  /* Get the index for the top-level list */
-  top = g_list_find (project->priv->tree, glade_widget_get_object (toplevel));
-
-  /* While the project is disposing widgets are unparented and sometimes no longer in the tree */
-  if (top)
-    gtk_tree_path_prepend_index (path, g_list_position (project->priv->tree, top));
-  else
-    gtk_tree_path_prepend_index (path, 0);
-  
-  return path;
+  return menu;
 }
 
-static void
-glade_project_model_get_value (GtkTreeModel *model,
-                               GtkTreeIter *iter,
-                               gint column,
-                               GValue *value)
+/**
+ * glade_project_redo_items:
+ * @project: A #GladeProject
+ *
+ * Creates a menu of the undo items in the project stack
+ *
+ * Returns: A newly created menu
+ */
+GtkWidget *
+glade_project_redo_items (GladeProject *project)
 {
-  GObject *object;
-  GladeWidget *widget;
-  GladeProperty *ref_prop;
-  gchar *str = NULL, *child_type;
-
-  g_return_if_fail (VALID_ITER (model, iter));
-
-  object = iter->user_data;
-  widget = glade_widget_get_from_gobject (object);
+  GtkWidget *menu = NULL;
+  GtkWidget *item;
+  GladeCommand *cmd;
+  GList *l;
 
-  value = g_value_init (value,
-                        glade_project_model_get_column_type (model, column));
+  g_return_val_if_fail (project != NULL, NULL);
 
-  switch (column)
+  for (l = project->priv->prev_redo_item ?
+       project->priv->prev_redo_item->next :
+       project->priv->undo_stack; l; l = walk_command (l, TRUE))
     {
-      case GLADE_PROJECT_MODEL_COLUMN_ICON_NAME:
-        g_object_get (glade_widget_get_adaptor (widget), "icon-name", &str, NULL);
-        g_value_take_string (value, str);
-        break;
-      case GLADE_PROJECT_MODEL_COLUMN_NAME:
-        g_value_set_string (value, glade_widget_get_name (widget));
-        break;
-      case GLADE_PROJECT_MODEL_COLUMN_TYPE_NAME:
-        g_value_set_static_string (value, G_OBJECT_TYPE_NAME (object));
-        break;
-      case GLADE_PROJECT_MODEL_COLUMN_OBJECT:
-        g_value_set_object (value, object);
-        break;
-      case GLADE_PROJECT_MODEL_COLUMN_MISC:
-        /* special child type / internal child */
-        if (glade_widget_get_internal (widget) != NULL)
-          str = g_strdup_printf (_("(internal %s)"),
-                                 glade_widget_get_internal (widget));
-        else if ((child_type =
-                  g_object_get_data (glade_widget_get_object (widget),
-                                     "special-child-type")) != NULL)
-          str = g_strdup_printf (_("(%s child)"), child_type);
-        else if (glade_widget_get_is_composite (widget))
-          str = g_strdup_printf (_("(template)"));
-        else if ((ref_prop = 
-                  glade_widget_get_parentless_widget_ref (widget)) != NULL)
-        {
-          GladePropertyClass *pclass     = glade_property_get_class (ref_prop);
-          GladeWidget        *ref_widget = glade_property_get_widget (ref_prop);
+      cmd = l->data;
 
-          /* translators: refers to a property named '%s' of widget '%s' */
-          str = g_strdup_printf (_("(%s of %s)"), 
-                                 glade_property_class_get_name (pclass),
-                                 glade_widget_get_name (ref_widget));
-        }
+      if (!menu)
+        menu = gtk_menu_new ();
 
-        g_value_take_string (value, str);
-        break;
-      case GLADE_PROJECT_MODEL_COLUMN_WARNING:
-        g_value_set_string (value, glade_widget_support_warning (widget));
-       break;
+      item = gtk_menu_item_new_with_label (glade_command_description (cmd));
+      gtk_widget_show (item);
+      gtk_menu_shell_append (GTK_MENU_SHELL (menu), GTK_WIDGET (item));
+      g_object_set_data (G_OBJECT (item), "command-data", cmd);
+
+      g_signal_connect (G_OBJECT (item), "activate",
+                        G_CALLBACK (redo_item_activated), project);
 
-      default:
-        g_assert_not_reached ();
     }
+
+  return menu;
 }
 
-static gboolean
-glade_project_model_iter_next (GtkTreeModel *model, GtkTreeIter *iter)
+void
+glade_project_reset_path (GladeProject *project)
 {
-  GladeProject *project = GLADE_PROJECT (model);
-  GObject *object = iter->user_data;
-  GladeWidget *widget;
-  GladeWidget *parent;
-  GList *children;
-  GList *child;
-  GList *next;
-  gboolean retval = FALSE;
+  g_return_if_fail (GLADE_IS_PROJECT (project));
+  project->priv->path = (g_free (project->priv->path), NULL);
+}
 
-  g_return_val_if_fail (VALID_ITER (project, iter), FALSE);
+/**
+ * glade_project_resource_fullpath:
+ * @project: The #GladeProject.
+ * @resource: The resource basename
+ *
+ * Project resource strings may be relative or fullpaths, but glade
+ * always expects a copy in the glade file directory, this function
+ * is used to make a local path to the file.
+ *
+ * Returns: A newly allocated string holding the 
+ *          local path the the project resource.
+ */
+gchar *
+glade_project_resource_fullpath (GladeProject *project, const gchar *resource)
+{
+  gchar *fullpath, *project_dir = NULL, *basename;
 
-  widget = glade_widget_get_from_gobject (object);
-  parent = glade_widget_get_parent (widget);
+  g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
 
-  if (parent)
-    {
-      children = glade_widget_get_children (parent);
-    }
+  basename = g_path_get_basename (resource);
+
+  if (project->priv->path == NULL)
+    project_dir = g_get_current_dir ();
   else
-    {
-      children = project->priv->tree;
-    }
+    project_dir = g_path_get_dirname (project->priv->path);
 
-  child = g_list_find (children, object);
-  if (child)
+  if (project->priv->resource_path)
     {
-      /* Get the next child that is actually in the project */
-      for (next = child->next; next; next = next->next)
-        {
-          GObject *object = next->data;
-
-          if (glade_project_has_object (project, object))
-            break;
-        }
-
-      if (next)
-        {
-          glade_project_model_get_iter_for_object (project, next->data, iter);
-          retval = TRUE;
-        }
+      if (g_path_is_absolute (project->priv->resource_path))
+        fullpath =
+            g_build_filename (project->priv->resource_path, basename, NULL);
+      else
+        fullpath =
+            g_build_filename (project_dir, project->priv->resource_path,
+                              basename, NULL);
     }
-  if (children != project->priv->tree)
-    g_list_free (children);
+  else
+    fullpath = g_build_filename (project_dir, basename, NULL);
 
-  return retval;
+  g_free (project_dir);
+  g_free (basename);
+
+  return fullpath;
 }
 
-static gboolean
-glade_project_model_iter_has_child (GtkTreeModel *model, GtkTreeIter *iter)
+/**
+ * glade_project_widget_visibility_changed:
+ * @project: The #GladeProject.
+ * @widget: The widget which visibility changed
+ * @visible: widget visibility value
+ *
+ * Emmits  GladeProject::widget-visibility-changed signal
+ *
+ */
+void
+glade_project_widget_visibility_changed (GladeProject  *project,
+                                         GladeWidget   *widget,
+                                         gboolean       visible)
 {
-  GladeProject *project = GLADE_PROJECT (model);
-  GladeWidget  *widget;
-
-  g_return_val_if_fail (VALID_ITER (model, iter), FALSE);
-
-  widget = glade_widget_get_from_gobject (iter->user_data);
-
-  if (glade_project_count_children (project, widget) > 0)
-    return TRUE;
+  g_return_if_fail (GLADE_IS_PROJECT (project));
+  g_return_if_fail (project == glade_widget_get_project (widget));
 
-  return FALSE;
+  g_signal_emit (project, glade_project_signals[WIDGET_VISIBILITY_CHANGED], 0,
+                 widget, visible);
 }
 
-static gint
-glade_project_model_iter_n_children (GtkTreeModel *model, GtkTreeIter *iter)
+const gchar *
+glade_project_get_path (GladeProject *project)
 {
-  GladeProject *project = GLADE_PROJECT (model);
-
-  g_return_val_if_fail (iter == NULL || VALID_ITER (project, iter), 0);
+  g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
 
-  if (iter)
-    {
-      GladeWidget *widget = glade_widget_get_from_gobject (iter->user_data);
+  return project->priv->path;
+}
 
-      return glade_project_count_children (project, widget);
-    }
+gchar *
+glade_project_get_name (GladeProject *project)
+{
+  g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
 
-  return g_list_length (project->priv->tree);
+  if (project->priv->path)
+    return g_filename_display_basename (project->priv->path);
+  else
+    return g_strdup_printf (_("Unsaved %i"), project->priv->unsaved_number);
 }
 
-static gboolean
-glade_project_model_iter_nth_child (GtkTreeModel *model,
-                                    GtkTreeIter *iter,
-                                    GtkTreeIter *parent,
-                                    gint nth)
+/**
+ * glade_project_is_loading:
+ * @project: A #GladeProject
+ *
+ * Returns: Whether the project is being loaded or not
+ *       
+ */
+gboolean
+glade_project_is_loading (GladeProject *project)
 {
-  GladeProject *project = GLADE_PROJECT (model);
-  GObject      *object = NULL;
+  g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
 
-  g_return_val_if_fail (parent == NULL || VALID_ITER (project, parent), FALSE);
+  return project->priv->loading;
+}
 
-  if (parent != NULL)
-    {
-      GObject     *obj    = parent->user_data;
-      GladeWidget *widget = glade_widget_get_from_gobject (obj);
+time_t
+glade_project_get_file_mtime (GladeProject *project)
+{
+  g_return_val_if_fail (GLADE_IS_PROJECT (project), 0);
 
-      object = glade_project_nth_child (project, widget, nth);
-    }
-  else if (project->priv->tree)
-    {
-      GList *child = g_list_nth (project->priv->tree, nth);
+  return project->priv->mtime;
+}
 
-      if (child)
-        object = child->data;
-    }
+/**
+ * glade_projects_get_objects:
+ * @project: a GladeProject
+ *
+ * Returns: List of all objects in this project
+ */
+const GList *
+glade_project_get_objects (GladeProject *project)
+{
+  g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
 
-  if (object)
-    {
-      glade_project_model_get_iter_for_object (project, object, iter);
-      return TRUE;
-    }
+  return project->priv->objects;
+}
 
-  iter->stamp     = 0;
-  iter->user_data = NULL;
+/**
+ * glade_project_properties:
+ * @project: A #GladeProject
+ *
+ * Runs a document properties dialog for @project.
+ */
+void
+glade_project_properties (GladeProject *project)
+{
+  g_return_if_fail (GLADE_IS_PROJECT (project));
 
-  return FALSE;
+  gtk_window_present (GTK_WINDOW (project->priv->prefs_dialog));
 }
 
-static gboolean
-glade_project_model_iter_children (GtkTreeModel *model,
-                                   GtkTreeIter *iter,
-                                   GtkTreeIter *parent)
+gchar *
+glade_project_display_dependencies (GladeProject *project)
 {
-  GladeProject *project = GLADE_PROJECT (model);
-  GObject      *object  = NULL;
+  GList *catalogs, *l;
+  GString *string;
 
-  g_return_val_if_fail (parent == NULL || VALID_ITER (project, parent), FALSE);
+  g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
 
-  if (parent)
+  string = g_string_new ("");
+
+  catalogs = glade_project_required_libs (project);
+  for (l = catalogs; l; l = l->next)
     {
-      GladeWidget *widget = glade_widget_get_from_gobject (parent->user_data);
+      gchar *catalog = l->data;
+      gint major = 0, minor = 0;
 
-      object = glade_project_nth_child (project, widget, 0);
-    }
-  else if (project->priv->tree)
-    object = project->priv->tree->data;
+      glade_project_get_target_version (project, catalog, &major, &minor);
 
-  if (object)
-    {
-      glade_project_model_get_iter_for_object (project, object, iter);
-      return TRUE;
+      if (l != catalogs)
+        g_string_append (string, ", ");
+
+      /* Capitalize GTK+ */
+      if (strcmp (catalog, "gtk+") == 0)
+        g_string_append_printf (string, "GTK+ >= %d.%d", major, minor);
+      else if (major && minor)
+        g_string_append_printf (string, "%s >= %d.%d", catalog, major, minor);
+      else
+        g_string_append_printf (string, "%s", catalog);
+
+      g_free (catalog);
     }
+  g_list_free (catalogs);
 
-  iter->stamp = 0;
-  iter->user_data = NULL;
-  return FALSE;
+  return g_string_free (string, FALSE);
 }
 
-static gboolean
-glade_project_model_iter_parent (GtkTreeModel *model,
-                                 GtkTreeIter *iter,
-                                 GtkTreeIter *child)
+/**
+ * glade_project_toplevels:
+ * @project: a #GladeProject
+ *
+ * Returns: a #GList containing the #GtkWidget toplevel items in @project
+ */
+GList *
+glade_project_toplevels (GladeProject *project)
 {
-  GladeProject *project = GLADE_PROJECT (model);
-  GladeWidget *widget;
-  GladeWidget *parent;
+  g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
 
-  g_return_val_if_fail (VALID_ITER (project, child), FALSE);
+  return project->priv->tree;
+}
 
-  widget = glade_widget_get_from_gobject (child->user_data);
-  parent = glade_widget_get_parent (widget);
+/**
+ * glade_project_set_translation_domain:
+ * @project: a #GladeProject
+ * @domain: the translation domain
+ *
+ * Set the project translation domain.
+ */
+void
+glade_project_set_translation_domain (GladeProject *project, const gchar *domain)
+{
+  GladeProjectPrivate *priv;
 
-  if (parent && 
-      glade_project_has_object (project, glade_widget_get_object (parent)))
-    {
-      glade_project_model_get_iter_for_object (project,
-                                               glade_widget_get_object (parent),
-                                               iter);
-      return TRUE;
-    }
+  g_return_if_fail (GLADE_IS_PROJECT (project));
 
-  iter->stamp = 0;
-  iter->user_data = NULL;
+  priv = project->priv;
 
-  return FALSE;
+  if (g_strcmp0 (priv->translation_domain, domain))
+    {
+      g_free (priv->translation_domain);
+      priv->translation_domain = g_strdup (domain);
+
+      g_object_notify_by_pspec (G_OBJECT (project),
+                                glade_project_props[PROP_TRANSLATION_DOMAIN]);
+    }
 }
 
-static void
-gtk_tree_model_iface_init (GtkTreeModelIface *iface)
+/**
+ * glade_project_get_translation_domain:
+ * @project: a #GladeProject
+ *
+ * Returns: the translation domain
+ */
+const gchar *
+glade_project_get_translation_domain (GladeProject *project)
 {
-  iface->get_flags = glade_project_model_get_flags;
-  iface->get_column_type = glade_project_model_get_column_type;
-  iface->get_n_columns = glade_project_model_get_n_columns;
-  iface->get_iter = glade_project_model_get_iter;
-  iface->get_path = glade_project_model_get_path;
-  iface->get_value = glade_project_model_get_value;
-  iface->iter_next = glade_project_model_iter_next;
-  iface->iter_children = glade_project_model_iter_children;
-  iface->iter_has_child = glade_project_model_iter_has_child;
-  iface->iter_n_children = glade_project_model_iter_n_children;
-  iface->iter_nth_child = glade_project_model_iter_nth_child;
-  iface->iter_parent = glade_project_model_iter_parent;
-}
+  g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
 
+  return project->priv->translation_domain;
+}
 
 /*************************************************
  *                Command Central                *
diff --git a/gladeui/glade-project.h b/gladeui/glade-project.h
index a78ab26..1f37291 100644
--- a/gladeui/glade-project.h
+++ b/gladeui/glade-project.h
@@ -154,6 +154,9 @@ void                glade_project_preview              (GladeProject       *proj
 void                glade_project_properties           (GladeProject       *project);
 gchar              *glade_project_resource_fullpath    (GladeProject       *project,
                                                         const gchar        *resource);
+void                glade_project_set_resource_path    (GladeProject       *project,
+                                                        const gchar        *path);
+const gchar        *glade_project_get_resource_path    (GladeProject       *project);
 
 void                glade_project_widget_visibility_changed (GladeProject  *project,
                                                              GladeWidget   *widget,
@@ -251,6 +254,9 @@ void                glade_project_set_translation_domain (GladeProject *project,
 const gchar        *glade_project_get_translation_domain (GladeProject *project);
 
 /* Verifications */
+gboolean            glade_project_verify               (GladeProject       *project,
+                                                       gboolean            saving,
+                                                       GladeVerifyFlags    flags);
 gchar              *glade_project_verify_widget_adaptor(GladeProject       *project,
                                                         GladeWidgetAdaptor *adaptor,
                                                         GladeSupportMask   *mask);
diff --git a/po/POTFILES.in b/po/POTFILES.in
index eb41f4d..d3c4155 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -33,6 +33,7 @@ gladeui/glade-popup.c
 gladeui/glade-preview.c
 gladeui/glade-previewer.c
 gladeui/glade-project.c
+gladeui/glade-project-properties.c
 gladeui/glade-property.c
 gladeui/glade-property-class.c
 gladeui/glade-property-label.c


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