[glade] Created GladeProjectProperties dialog
- From: Tristan Van Berkom <tvb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glade] Created GladeProjectProperties dialog
- Date: Sat, 20 Apr 2013 08:10:38 +0000 (UTC)
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]