[glade3] 2010-10-12 Marco Diego Aurélio Mesquita <marcodiegomesquita gmail com>



commit 0b6f713fbbddbc51c556418b3145b6c46a5df23c
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date:   Tue Oct 12 17:49:14 2010 +0900

    2010-10-12  Marco Diego Aurélio Mesquita <marcodiegomesquita gmail com>
    
    	Implemented preview feature for Glade.
    
    	* gladeui/Makefile.am, gladeui/glade-previewer.c: Added program to preview
    	  glade files.
    
    	* gladeui/glade-project.[ch]: Implemented glade_project_preview() to spawn a
    	  child preview process, reap it when it dies and close all previews when
    	  project closes.
    
    	* src/glade-window.c: Added toolbar button to spawn the preview.
    
    	* gladeui/glade-xml-utils.[ch]: Added glade_xml_dump_from_context().
    
    	* plugins/gtk+/glade-gtk.c, plugins/gtk+/gtk+.xml.in: Added actions to preview a widget.
    
    	* gladeui/glade-app.[ch]: Added glade_app_get_bin_dir() for resolving of previewer path.

 ChangeLog                 |   19 ++++
 gladeui/.gitignore        |    2 +
 gladeui/Makefile.am       |   39 +++++++-
 gladeui/glade-app.c       |   13 +++
 gladeui/glade-app.h       |    2 +
 gladeui/glade-project.c   |  247 ++++++++++++++++++++++++++++++++++++++++++++-
 gladeui/glade-project.h   |    8 +-
 gladeui/glade-xml-utils.c |   16 +++
 gladeui/glade-xml-utils.h |    3 +
 plugins/gtk+/glade-gtk.c  |   10 ++-
 plugins/gtk+/gtk+.xml.in  |    1 +
 src/glade-window.c        |   87 ++++++++++++++++-
 12 files changed, 436 insertions(+), 11 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 33fad2c..108f2f8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2010-10-12  Marco Diego Aurélio Mesquita <marcodiegomesquita gmail com>
+
+	Implemented preview feature for Glade.
+
+	* gladeui/Makefile.am, gladeui/glade-previewer.c: Added program to preview
+	  glade files.
+
+	* gladeui/glade-project.[ch]: Implemented glade_project_preview() to spawn a
+	  child preview process, reap it when it dies and close all previews when
+	  project closes.
+
+	* src/glade-window.c: Added toolbar button to spawn the preview.
+
+	* gladeui/glade-xml-utils.[ch]: Added glade_xml_dump_from_context().
+
+	* plugins/gtk+/glade-gtk.c, plugins/gtk+/gtk+.xml.in: Added actions to preview a widget.
+
+	* gladeui/glade-app.[ch]: Added glade_app_get_bin_dir() for resolving of previewer path.
+
 2010-10-11  Tristan Van Berkom <tristanvb openismus com>
 
 	* gladeui/glade-inspector.c: Fixed project leakage at dispose time.
diff --git a/gladeui/.gitignore b/gladeui/.gitignore
index b0093fe..797b4d8 100644
--- a/gladeui/.gitignore
+++ b/gladeui/.gitignore
@@ -1,3 +1,5 @@
 /glade-marshallers.c
 /glade-marshallers.h
 /gladeui.rc
+
+/glade-previewer
diff --git a/gladeui/Makefile.am b/gladeui/Makefile.am
index 3db8f91..df0e4b6 100644
--- a/gladeui/Makefile.am
+++ b/gladeui/Makefile.am
@@ -1,16 +1,51 @@
+## Previewer
+
+bin_PROGRAMS = glade-previewer
+
+glade_previewer_CPPFLAGS = \
+	-I$(top_srcdir)    \
+	-I$(top_builddir)  \
+	-DGLADE_GNOMEHELPDIR="\"$(HELP_DIR)\""
+	$(AM_CPPFLAGS)
+
+glade_previewer_CFLAGS =   \
+	$(GTK_CFLAGS)      \
+	$(IGE_MAC_CFLAGS)  \
+	$(WARN_CFLAGS)     \
+	$(AM_CFLAGS)
+
+glade_previewer_LDFLAGS = $(AM_LDFLAGS)
+
+glade_previewer_LDADD = $(top_builddir)/gladeui/libgladeui-2.la $(IGE_MAC_LIBS)
+
+glade_previewer_SOURCES = \
+	glade-previewer.c
+
+if NATIVE_WIN32
+glade_previewer_LDADD += glade-win32-res.o
+if !GLADE_UNSTABLE
+glade_previewer_LDFLAGS += -mwindows
+endif
+endif
+
+glade-win32-res.o: glade-previewer.rc
+	$(WINDRES) $< $@
+
+## Rest of the UI ;)
 
 common_defines = \
 	-DG_LOG_DOMAIN=\"GladeUI\"                      \
 	-DGLADE_CATALOGSDIR="\"$(pkgdatadir)/catalogs\""\
 	-DGLADE_MODULESDIR="\"$(pkglibdir)/modules\""	\
 	-DGLADE_PIXMAPSDIR="\"$(pkgdatadir)/pixmaps\""	\
-	-DGLADE_LOCALEDIR="\"$(datadir)/locale\""
+	-DGLADE_LOCALEDIR="\"$(datadir)/locale\""\
+  -DGLADE_BINDIR="\"$(bindir)\""
 
 lib_LTLIBRARIES = libgladeui-2.la
 
 BUILT_SOURCES = glade-marshallers.c glade-marshallers.h
 
-EXTRA_DIST = glade-marshallers.list gladeui.rc.in icon-naming-spec.c
+EXTRA_DIST = glade-marshallers.list gladeui.rc.in icon-naming-spec.c glade-previewer.rc.in
 
 # The glade-3 core library
 libgladeui_2_la_SOURCES = \
diff --git a/gladeui/glade-app.c b/gladeui/glade-app.c
index 81259b9..363d0ee 100644
--- a/gladeui/glade-app.c
+++ b/gladeui/glade-app.c
@@ -103,6 +103,7 @@ static gchar *catalogs_dir = NULL;
 static gchar *modules_dir  = NULL;
 static gchar *pixmaps_dir  = NULL;
 static gchar *locale_dir   = NULL;
+static gchar *bin_dir      = NULL;
 
 static GladeApp *singleton_app = NULL;
 static gboolean check_initialised = FALSE;
@@ -199,6 +200,7 @@ glade_app_finalize (GObject *app)
 	g_free (modules_dir);
 	g_free (pixmaps_dir);	
 	g_free (locale_dir);
+	g_free (bin_dir);
 
 	singleton_app = NULL;
 	check_initialised = FALSE;
@@ -354,6 +356,15 @@ glade_app_get_locale_dir (void)
 	return locale_dir;
 }
 
+const gchar *
+glade_app_get_bin_dir (void)
+{
+	glade_init_check ();
+	
+	return bin_dir;
+}
+
+
 /* build package paths at runtime */
 static void
 build_package_paths (void)
@@ -374,6 +385,7 @@ build_package_paths (void)
 	catalogs_dir = g_build_filename (prefix, "share", PACKAGE, "catalogs", NULL);
 	modules_dir  = g_build_filename (prefix, "lib", PACKAGE, "modules", NULL);
 	locale_dir   = g_build_filename (prefix, "share", "locale", NULL);
+	bin_dir      = g_build_filename (prefix, "bin", NULL);
 
 	g_free (prefix);
 #else
@@ -381,6 +393,7 @@ build_package_paths (void)
 	modules_dir  = g_strdup (GLADE_MODULESDIR);
 	pixmaps_dir  = g_strdup (GLADE_PIXMAPSDIR);
 	locale_dir   = g_strdup (GLADE_LOCALEDIR);
+	bin_dir      = g_strdup (GLADE_BINDIR);
 #endif
 }
 
diff --git a/gladeui/glade-app.h b/gladeui/glade-app.h
index 6892416..b5f2e04 100644
--- a/gladeui/glade-app.h
+++ b/gladeui/glade-app.h
@@ -208,6 +208,8 @@ const gchar       *glade_app_get_pixmaps_dir   (void) G_GNUC_CONST;
 
 const gchar       *glade_app_get_locale_dir    (void) G_GNUC_CONST;
 
+const gchar       *glade_app_get_bin_dir       (void) G_GNUC_CONST;
+
 G_END_DECLS
 
 #endif /* __GLADE_APP_H__ */
diff --git a/gladeui/glade-project.c b/gladeui/glade-project.c
index dd7d162..317bb20 100644
--- a/gladeui/glade-project.c
+++ b/gladeui/glade-project.c
@@ -74,7 +74,8 @@ enum
 	PROP_HAS_SELECTION,
 	PROP_PATH,
 	PROP_READ_ONLY,
-	PROP_FORMAT
+	PROP_FORMAT,
+	PROP_PREVIEWABLE
 };
 
 struct _GladeProjectPrivate
@@ -95,6 +96,8 @@ struct _GladeProjectPrivate
 			       * requested
 			       */
 
+	gboolean previewable;
+
 	gint   stamp;     /* A a random int per instance of project used to stamp/check the
 			   * GtkTreeIter->stamps */
 	GList *tree;      /* List of toplevel Objects in this projects */
@@ -155,6 +158,9 @@ struct _GladeProjectPrivate
 	GtkWidget *resource_fullpath_radio;
 	GtkWidget *relative_path_entry;
 	GtkWidget *full_path_button;
+
+	/* Store preview processes, so we can kill them on close */
+	GHashTable *preview_channels;
 };
 
 typedef struct {
@@ -167,6 +173,11 @@ typedef struct {
 	gchar *filename;
 } StockFilePair;
 
+typedef struct {
+	GIOChannel *channel;
+	guint watch;
+} ChannelWatchPair;
+
 
 static void         glade_project_set_target_version       (GladeProject *project,
 							    const gchar  *catalog,
@@ -362,6 +373,9 @@ glade_project_get_property (GObject    *object,
 		case PROP_FORMAT:
 			g_value_set_int (value, project->priv->format);
 			break;
+		case PROP_PREVIEWABLE:
+			g_value_set_boolean (value, project->priv->previewable);
+			break;
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 			break;			
@@ -570,6 +584,70 @@ glade_project_push_undo_impl (GladeProject *project, GladeCommand *cmd)
 }
 
 static void
+glade_project_preview_exits (GPid pid, gint status, gpointer data)
+{
+	GladeProject *project = (GladeProject *)data;
+	ChannelWatchPair *channel_watch;
+	GIOChannel *channel;
+	gchar *pidstr = g_strdup_printf ("%d", pid);
+
+	channel_watch = g_hash_table_lookup (project->priv->preview_channels, pidstr);
+	channel = channel_watch->channel;
+	g_io_channel_unref (channel);
+	g_hash_table_remove (project->priv->preview_channels, pidstr);
+
+	g_free (pidstr);
+	g_free (channel_watch);
+}
+
+static void
+glade_project_kill_previews (gpointer key,
+			     gpointer value,
+			     gpointer user_data)
+{
+	const gchar *quit = "<quit>";
+	GIOChannel *channel;
+	ChannelWatchPair *channel_watch = (ChannelWatchPair *) value;
+	GError *error = NULL;
+	gsize size;
+
+	channel = channel_watch->channel;
+	/* Removing watch, since the child will commit suicide */
+	g_source_remove (channel_watch->watch);
+	g_io_channel_write_chars (channel, quit, strlen (quit), &size, &error);
+
+	if (size != strlen (quit) && error != NULL)
+	{
+		g_printerr ("Error passing quit signal trough pipe: %s", error->message);
+		g_error_free (error);
+	}
+
+	g_io_channel_flush (channel, &error);
+	if (error != NULL)
+	{
+		g_printerr ("Error flushing channel: %s", error->message);
+		g_error_free (error);
+	}
+
+	g_io_channel_shutdown (channel, TRUE, &error);
+	if (error != NULL)
+	{
+		g_printerr ("Error shutting down channel: %s", error->message);
+		g_error_free (error);
+	}
+
+	g_io_channel_unref (channel);
+	g_free (channel_watch);
+}
+
+static void
+glade_project_close_impl (GladeProject *project)
+{
+	g_hash_table_foreach (project->priv->preview_channels, glade_project_kill_previews, project);
+	g_hash_table_unref (project->priv->preview_channels);
+}
+
+static void
 glade_project_changed_impl (GladeProject *project, 
 			    GladeCommand *command,
 			    gboolean      forward)
@@ -612,6 +690,8 @@ glade_project_init (GladeProject *project)
 	priv->first_modification = NULL;
 	priv->first_modification_is_na = FALSE;
 
+	priv->preview_channels = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+	priv->previewable = FALSE;
 	priv->toplevel_names = glade_name_context_new ();
 	priv->naming_policy = GLADE_POLICY_PROJECT_WIDE;
 
@@ -672,9 +752,9 @@ glade_project_class_init (GladeProjectClass *klass)
 
 	klass->widget_name_changed = NULL;
 	klass->selection_changed   = NULL;
-	klass->close               = NULL;
+	klass->close               = glade_project_close_impl;
 	klass->changed             = glade_project_changed_impl;
-	
+
 	/**
 	 * GladeProject::add-widget:
 	 * @gladeproject: the #GladeProject which received the signal.
@@ -879,6 +959,16 @@ glade_project_class_init (GladeProjectClass *klass)
 							   GLADE_PROJECT_FORMAT_GTKBUILDER,
 							   G_PARAM_READABLE));
 
+	g_object_class_install_property (object_class,
+					 PROP_PREVIEWABLE,
+					 g_param_spec_boolean ("previewable",
+							      _("Previewable"),
+							      _("Wether the project can be previewed"),
+							      FALSE,
+							      G_PARAM_READABLE));
+
+
+
 	g_type_class_add_private (klass, sizeof (GladeProjectPrivate));
 }
 
@@ -1721,6 +1811,118 @@ glade_project_save (GladeProject *project, const gchar *path, GError **error)
 	return ret > 0;
 }
 
+static GPid
+glade_project_launch_preview (GladeProject *project, gchar *buffer, GtkWidget *widget)
+{
+	GPid pid;
+	GError *error = NULL;
+	gchar *argv[4];
+	gint child_stdin;
+	GIOChannel *output;
+	guint watch;
+	ChannelWatchPair *channel_watch;
+	GladeWidget *glade_widget;
+	
+
+	#ifdef WINDOWS
+	argv[0] = g_build_filename (glade_app_get_bin_dir(), "glade-previewer.exe", NULL);
+	#else
+	argv[0] = g_build_filename (glade_app_get_bin_dir(), "glade-previewer", NULL);
+	#endif
+
+
+	argv[1] = "--listen";
+
+	if (widget != NULL)
+	{
+		glade_widget = glade_widget_get_from_gobject (G_OBJECT (widget));
+		argv[2] = g_strdup_printf ("--toplevel=%s", glade_widget->name);
+		argv[3] = NULL;
+	}
+
+	if (g_spawn_async_with_pipes (NULL,
+				      argv,
+				      NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL,
+				      &pid, &child_stdin, NULL, NULL, &error) == FALSE)
+	{
+		g_printerr (_("Error launching previewer: %s\n"), error->message);
+		glade_util_ui_message (glade_app_get_window(),
+				       GLADE_UI_ERROR, NULL,
+				       _("Failed to launch preview: %s.\n"),
+				       error->message);
+		g_error_free (error);
+		pid = 0;
+		goto end;
+	}
+
+	/* Store watch so we can remove it later */
+	watch = g_child_watch_add (pid, glade_project_preview_exits, project);
+
+	#ifdef WINDOWS
+	output = g_io_channel_win32_new_fd (child_stdin);
+	#else
+	output = g_io_channel_unix_new (child_stdin);
+	#endif
+
+	gsize bytes_written;
+	g_io_channel_write_chars (output, buffer, strlen (buffer), &bytes_written, &error);
+
+	if (bytes_written != strlen (buffer) && error != NULL)
+	{
+		g_printerr ("Error passing UI trough pipe: %s", error->message);
+		g_error_free (error);
+	}
+
+	g_io_channel_flush (output, &error);
+	if (error != NULL)
+	{
+		g_printerr ("Error flushing UI trough pipe: %s", error->message);
+		g_error_free (error);
+	}
+
+	if (widget != NULL) g_free (argv[2]);
+
+	/* Adding channel to list of channels */
+	channel_watch = g_new (ChannelWatchPair, 1);
+	channel_watch->channel = output;
+	channel_watch->watch = watch;
+	g_hash_table_insert (project->priv->preview_channels, g_strdup_printf("%d", pid),
+							      channel_watch);
+
+	end:
+	g_free (argv[0]);
+	return pid;
+}
+
+/**
+ * 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;
+	GtkWidget *widget = GTK_WIDGET (gwidget->object);
+
+	g_return_if_fail (GTK_WIDGET (widget));
+	g_return_if_fail (GLADE_IS_PROJECT (project));
+
+	context = glade_project_write (project);
+
+	text = glade_xml_dump_from_context (context);
+
+	glade_project_launch_preview (project, text, widget);
+
+	g_free(text);
+}
+
 /*******************************************************************
      Verify code here (versioning, incompatability checks)
  *******************************************************************/
@@ -2648,6 +2850,34 @@ sort_project_dependancies (GObject *a, GObject *b)
 		return 1;
 }
 
+static gboolean
+glade_project_has_widget (GladeProject *project)
+{
+	GtkWidget *widget = NULL;
+	const GList *objects;
+
+	objects = glade_project_get_objects (project);
+
+	while (objects != NULL)
+	{
+		if (GTK_IS_WIDGET (objects->data))
+		{
+			widget = GTK_WIDGET(objects->data);
+			break;
+		}
+		objects = objects->next;
+	}
+
+	return widget != NULL;
+}
+
+static void
+glade_project_update_previewable (GladeProject *project)
+{
+	project->priv->previewable = glade_project_has_widget (project);
+	g_object_notify (G_OBJECT (project), "previewable");
+}
+
 /**
  * glade_project_add_object:
  * @project: the #GladeProject the widget is added to
@@ -2742,8 +2972,9 @@ glade_project_add_object (GladeProject *project,
 		g_list_free (children);
 	}
 
-	/* Update user visible compatability info */
+	/* Update user visible compatibility info */
 	glade_project_verify_properties (gwidget);
+	glade_project_update_previewable (project);
 	
 	g_signal_emit (G_OBJECT (project),
 		       glade_project_signals [ADD_WIDGET],
@@ -2833,6 +3064,8 @@ glade_project_remove_object (GladeProject *project, GObject *object)
 			       gwidget);
 		gtk_tree_iter_free (iter);
 	}
+
+	glade_project_update_previewable (project);
 }
 
 static void
@@ -3609,6 +3842,12 @@ glade_project_set_naming_policy (GladeProject       *project,
 
 }
 
+gboolean
+glade_project_get_previewable (GladeProject *project)
+{
+	return project->priv->previewable;
+}
+
 GladeNamingPolicy
 glade_project_get_naming_policy (GladeProject *project)
 {
diff --git a/gladeui/glade-project.h b/gladeui/glade-project.h
index ebffbb8..b8cf55b 100644
--- a/gladeui/glade-project.h
+++ b/gladeui/glade-project.h
@@ -95,8 +95,10 @@ GladeProject  *glade_project_load                (const gchar  *path);
 gboolean       glade_project_save                (GladeProject *project, 
 						  const gchar   *path, 
 						  GError       **error);
-						 
-const gchar   *glade_project_get_path            (GladeProject *project);						 
+
+void           glade_project_preview             (GladeProject *project, GladeWidget *gwidget);
+
+const gchar   *glade_project_get_path            (GladeProject *project);
 
 gchar         *glade_project_get_name            (GladeProject *project);
 
@@ -186,6 +188,8 @@ void           glade_project_set_instance_count   (GladeProject *project, guint
 
 gboolean       glade_project_get_modified         (GladeProject *project);
 
+gboolean       glade_project_get_previewable      (GladeProject *project);
+
 void           glade_project_set_format      	  (GladeProject *project, GladeProjectFormat format);
 
 GladeProjectFormat glade_project_get_format  	  (GladeProject *project);
diff --git a/gladeui/glade-xml-utils.c b/gladeui/glade-xml-utils.c
index e0bdeb0..c280c8f 100644
--- a/gladeui/glade-xml-utils.c
+++ b/gladeui/glade-xml-utils.c
@@ -758,6 +758,22 @@ glade_xml_context_get_doc (GladeXmlContext *context)
 	return context->doc;
 }
 
+gchar *
+glade_xml_dump_from_context (GladeXmlContext *context)
+{
+	GladeXmlDoc *doc;
+	xmlChar *string = NULL;
+	gchar *text;
+	int size;
+
+	doc = glade_xml_context_get_doc (context);
+	xmlDocDumpFormatMemory(&(doc->doc), &string, &size, 1);
+
+	text = claim_string (string);
+
+	return text;
+}
+
 gboolean
 glade_xml_node_is_comment (GladeXmlNode *node_in) 
 {
diff --git a/gladeui/glade-xml-utils.h b/gladeui/glade-xml-utils.h
index df12ba8..9fda0c8 100644
--- a/gladeui/glade-xml-utils.h
+++ b/gladeui/glade-xml-utils.h
@@ -281,6 +281,9 @@ GladeXmlContext * glade_xml_context_new_from_path (const gchar *full_path,
 						   const gchar *root_name);
 GladeXmlDoc *     glade_xml_context_get_doc (GladeXmlContext *context);
 
+/* Dumps an xml string from a context */
+gchar * glade_xml_dump_from_context (GladeXmlContext *context);
+
 gboolean        glade_xml_load_sym_from_node (GladeXmlNode     *node_in,
 					      GModule          *module,
 					      gchar            *tagname,
diff --git a/plugins/gtk+/glade-gtk.c b/plugins/gtk+/glade-gtk.c
index 3342e3d..2e33c3c 100644
--- a/plugins/gtk+/glade-gtk.c
+++ b/plugins/gtk+/glade-gtk.c
@@ -1029,13 +1029,21 @@ glade_gtk_widget_action_activate (GladeWidgetAdaptor *adaptor,
 	GladeWidget *gwidget = glade_widget_get_from_gobject (object), *gparent;
 	GList       this_widget = { 0, }, that_widget = { 0, };
 	GtkWidget   *parent = gtk_widget_get_parent (GTK_WIDGET (object));
+	GladeProject *project;
 
 	if (parent)
 		gparent = glade_widget_get_from_gobject (parent);
 	else
 		gparent = NULL;
 
-	if (strcmp (action_path, "edit_separate") == 0)
+	if (strcmp (action_path, "preview") == 0)
+	{
+		project = glade_widget_get_project (gwidget);
+		glade_project_preview (project,
+				       glade_widget_get_from_gobject((gpointer)object)
+				      );
+	}
+	else if (strcmp (action_path, "edit_separate") == 0)
 	{
 		GtkWidget *dialog = 
 			glade_editor_dialog_for_widget (gwidget);
diff --git a/plugins/gtk+/gtk+.xml.in b/plugins/gtk+/gtk+.xml.in
index 4db98cf..30fdb07 100644
--- a/plugins/gtk+/gtk+.xml.in
+++ b/plugins/gtk+/gtk+.xml.in
@@ -30,6 +30,7 @@
       </signals>
 
       <actions>
+	<action id="preview" _name="Preview snapshot"/>
         <action id="edit_separate" _name="Edit Separately" stock="gtk-edit"/>
         <action id="remove_parent" _name="Remove Parent" stock="gtk-remove"/>
         <action id="add_parent" _name="Add Parent" stock="gtk-add">
diff --git a/src/glade-window.c b/src/glade-window.c
index f88c55e..2ddfdbc 100644
--- a/src/glade-window.c
+++ b/src/glade-window.c
@@ -33,6 +33,8 @@
 #include <gladeui/glade-popup.h>
 #include <gladeui/glade-inspector.h>
 
+#include <gladeui/glade-project.h>
+
 #include <string.h>
 #include <glib/gstdio.h>
 #include <glib/gi18n.h>
@@ -117,6 +119,7 @@ struct _GladeWindowPrivate
 	gchar               *default_path;         /* the default path for open/save operations */
 	
 	GtkToggleToolButton *selector_button;      /* the widget selector button (replaces the one in the palette) */
+	GtkToolButton       *preview_button;	   /* the project preview button (replaces the one in the palette) */
 	GtkToggleToolButton *drag_resize_button;   /* sets the pointer to drag/resize mode */
 	gboolean             setting_pointer_mode; /* avoid feedback signal loops */
 
@@ -782,6 +785,50 @@ on_selector_button_toggled (GtkToggleToolButton *button, GladeWindow *window)
 }
 
 static void
+on_preview_button_clicked (GtkToggleToolButton *button, GladeWindow *window)
+{
+	GladeProject *project;
+
+	const GList *objects;
+
+	GtkWidget *widget = NULL;
+	GtkWidget *window_to_preview = NULL;
+	GladeWidget *glade_widget = NULL;
+
+	project = glade_design_view_get_project (window->priv->active_view);
+
+	if (project == NULL)
+		return;
+
+	objects = glade_project_get_objects (project);
+
+	while (objects != NULL)
+	{
+		if (GTK_IS_WIDGET (objects->data))
+		{
+			widget = GTK_WIDGET(objects->data);
+			if (GTK_IS_WINDOW (widget)) 
+			{
+				window_to_preview = widget;
+				break;
+			}
+		}
+		objects = objects->next;
+	}
+
+	if (widget != NULL)
+	{
+		glade_widget = glade_widget_get_from_gobject (G_OBJECT (widget));
+	}
+
+	if (window_to_preview != NULL) widget = window_to_preview;
+	glade_project_preview (project,
+			       glade_widget_get_from_gobject((gpointer)widget)
+			      );
+}
+
+
+static void
 on_drag_resize_button_toggled (GtkToggleToolButton *button, GladeWindow *window)
 {
 	if (window->priv->setting_pointer_mode)
@@ -2355,6 +2402,24 @@ create_selector_tool_button (GtkToolbar *toolbar)
 }
 
 static GtkWidget *
+create_preview_tool_button (GtkToolbar *toolbar)
+{
+	GtkToolItem  *button;
+	button = gtk_tool_button_new_from_stock (GTK_STOCK_EXECUTE);
+	gtk_tool_button_set_label (GTK_TOOL_BUTTON(button), _("Preview snapshot"));
+
+	gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (button),
+				   toolbar->tooltips,
+				   _("Previews snapshot of project"),
+				   NULL);
+
+	gtk_widget_show (GTK_WIDGET (button));
+
+	return GTK_WIDGET (button);
+}
+
+
+static GtkWidget *
 create_drag_resize_tool_button (GtkToolbar *toolbar)
 {
 	GtkToolItem  *button;
@@ -2466,6 +2531,10 @@ add_project (GladeWindow *window, GladeProject *project)
 
 	/* Kick the inspector in the balls here... */
 	glade_project_selection_changed (project);
+
+	/* Update preview button */
+	gtk_widget_set_sensitive ( GTK_WIDGET (window->priv->preview_button),
+					       glade_project_get_previewable (project));
 }
 
 void
@@ -2704,9 +2773,15 @@ refresh_undo_redo (GladeWindow *window)
 
 static void
 update_ui (GladeApp *app, GladeWindow *window)
-{      
+{
+	GladeProject *project;
 	if (window->priv->active_view)
+	{
+		project = glade_design_view_get_project (window->priv->active_view);
+		gtk_widget_set_sensitive ( GTK_WIDGET (window->priv->preview_button),
+					   glade_project_get_previewable (project));
 		gtk_widget_queue_draw (GTK_WIDGET (window->priv->active_view));
+	}
 
 	refresh_undo_redo (window);
 
@@ -3267,10 +3342,16 @@ glade_window_init (GladeWindow *window)
 	gtk_toolbar_insert (GTK_TOOLBAR (priv->toolbar), GTK_TOOL_ITEM (sep), -1);
 
 	priv->selector_button = 
-		GTK_TOGGLE_TOOL_BUTTON (create_selector_tool_button (GTK_TOOLBAR (priv->toolbar)));	
+		GTK_TOGGLE_TOOL_BUTTON (create_selector_tool_button (GTK_TOOLBAR (priv->toolbar)));
 	gtk_toolbar_insert (GTK_TOOLBAR (priv->toolbar), 
 			    GTK_TOOL_ITEM (priv->selector_button), -1);
 
+	priv->preview_button =
+		GTK_TOOL_BUTTON (create_preview_tool_button (GTK_TOOLBAR (priv->toolbar)));
+	gtk_toolbar_insert (GTK_TOOLBAR (priv->toolbar),
+			    GTK_TOOL_ITEM (priv->preview_button), -1);
+	gtk_widget_set_sensitive (GTK_WIDGET (priv->preview_button), FALSE);
+
 	priv->drag_resize_button = 
 		GTK_TOGGLE_TOOL_BUTTON (create_drag_resize_tool_button 
 					(GTK_TOOLBAR (priv->toolbar)));	
@@ -3282,6 +3363,8 @@ glade_window_init (GladeWindow *window)
 
 	g_signal_connect (G_OBJECT (priv->selector_button), "toggled",
 			  G_CALLBACK (on_selector_button_toggled), window);
+	g_signal_connect (G_OBJECT (priv->preview_button), "clicked",
+			  G_CALLBACK (on_preview_button_clicked), window);
 	g_signal_connect (G_OBJECT (priv->drag_resize_button), "toggled",
 			  G_CALLBACK (on_drag_resize_button_toggled), window);
 	g_signal_connect (G_OBJECT (glade_app_get()), "notify::pointer-mode",



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