[anjuta] git: Support viewing the log of any branch, not just the currently active one



commit 2d608c2db2b81ff7a689eb784ab7124490851241
Author: James Liggett <jrliggett cox net>
Date:   Sat May 23 22:04:23 2009 -0700

    git: Support viewing the log of any branch, not just the currently active one
---
 plugins/git/anjuta-git.ui     |   46 +++++++++-
 plugins/git/git-log-command.c |    8 ++-
 plugins/git/git-log-command.h |    1 +
 plugins/git/git-log-dialog.c  |  213 ++++++++++++++++++++++++++++++++++++++++-
 plugins/git/git-log-dialog.h  |    2 +
 plugins/git/plugin.c          |    3 +
 plugins/git/plugin.h          |    1 +
 7 files changed, 269 insertions(+), 5 deletions(-)

diff --git a/plugins/git/anjuta-git.ui b/plugins/git/anjuta-git.ui
index 2124c4b..3f3541a 100644
--- a/plugins/git/anjuta-git.ui
+++ b/plugins/git/anjuta-git.ui
@@ -1975,6 +1975,48 @@
           </packing>
         </child>
         <child>
+          <object class="GtkFrame" id="frame1">
+            <property name="visible">True</property>
+            <property name="label_xalign">0</property>
+            <property name="shadow_type">none</property>
+            <child>
+              <object class="GtkAlignment" id="alignment1">
+                <property name="visible">True</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <object class="GtkComboBox" id="log_branch_combo">
+                    <property name="visible">True</property>
+                    <property name="model">log_branch_combo_model</property>
+                    <child>
+                      <object class="GtkCellRendererPixbuf" id="log_branch_combo_active_icon"/>
+                      <attributes>
+                        <attribute name="stock-id">0</attribute>
+                      </attributes>
+                    </child>
+                    <child>
+                      <object class="GtkCellRendererText" id="log_branch_combo_name"/>
+                      <attributes>
+                        <attribute name="text">1</attribute>
+                      </attributes>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child type="label">
+              <object class="GtkLabel" id="label1">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">&lt;b&gt;Branch:&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
           <object class="GtkExpander" id="expander1">
             <property name="visible">True</property>
             <property name="can_focus">True</property>
@@ -2239,7 +2281,7 @@
           <packing>
             <property name="expand">False</property>
             <property name="fill">False</property>
-            <property name="position">1</property>
+            <property name="position">2</property>
           </packing>
         </child>
         <child>
@@ -2326,7 +2368,7 @@
             </child>
           </object>
           <packing>
-            <property name="position">2</property>
+            <property name="position">3</property>
           </packing>
         </child>
       </object>
diff --git a/plugins/git/git-log-command.c b/plugins/git/git-log-command.c
index 5f97df0..0513933 100644
--- a/plugins/git/git-log-command.c
+++ b/plugins/git/git-log-command.c
@@ -40,6 +40,7 @@ struct _GitLogCommandPriv
 	GRegex *author_regex;
 	GRegex *time_regex;
 	GRegex *short_log_regex;
+	gchar *branch;
 	gchar *path;
 	
 	/* Filters */
@@ -89,6 +90,7 @@ git_log_command_finalize (GObject *object)
 	g_regex_unref (self->priv->author_regex);
 	g_regex_unref (self->priv->time_regex);
 	g_regex_unref (self->priv->short_log_regex);
+	g_free (self->priv->branch);
 	g_free (self->priv->path);
 	
 	g_free (self->priv->author);
@@ -164,6 +166,9 @@ git_log_command_run (AnjutaCommand *command)
 		
 		g_string_free (commit_range, TRUE);
 	}
+
+	if (self->priv->branch)
+		git_command_add_arg (GIT_COMMAND (command), self->priv->branch);
 	else
 		git_command_add_arg (GIT_COMMAND (command), "HEAD");
 	
@@ -285,7 +290,7 @@ git_log_command_class_init (GitLogCommandClass *klass)
 
 GitLogCommand *
 git_log_command_new (const gchar *working_directory,
-					 const gchar *path,
+					 const gchar *branch, const gchar *path,
 					 const gchar *author, const gchar *grep,
 					 const gchar *since_date, const gchar *until_date,
 					 const gchar *since_commit,
@@ -300,6 +305,7 @@ git_log_command_new (const gchar *working_directory,
 	
 	self->priv->author = g_strdup (author);
 	self->priv->path = g_strdup (path);
+	self->priv->branch = g_strdup (branch);
 	self->priv->grep = g_strdup (grep);
 	self->priv->since_date = g_strdup (since_date);
 	self->priv->until_date = g_strdup (until_date);
diff --git a/plugins/git/git-log-command.h b/plugins/git/git-log-command.h
index e4d20a0..5d80600 100644
--- a/plugins/git/git-log-command.h
+++ b/plugins/git/git-log-command.h
@@ -57,6 +57,7 @@ struct _GitLogCommand
 
 GType git_log_command_get_type (void) G_GNUC_CONST;
 GitLogCommand *git_log_command_new (const gchar *working_directory,
+                                    const gchar *branch,
 									const gchar *path,
 									const gchar *author,
 									const gchar *grep,
diff --git a/plugins/git/git-log-dialog.c b/plugins/git/git-log-dialog.c
index e92b91b..12fdf08 100644
--- a/plugins/git/git-log-dialog.c
+++ b/plugins/git/git-log-dialog.c
@@ -242,6 +242,10 @@ on_ref_command_finished (AnjutaCommand *command, guint return_code,
 {
 	gchar *path;
 	const gchar *relative_path;
+	GtkWidget *log_branch_combo;
+	GtkTreeModel *log_branch_combo_model;
+	GtkTreeIter iter;
+	gchar *branch;
 	GtkWidget *log_changes_view;
 	GtkTreeViewColumn *graph_column;
 	gchar *author;
@@ -274,8 +278,15 @@ on_ref_command_finished (AnjutaCommand *command, guint return_code,
 	 * file or folder, hide the graph column, because we can't be assured that  
 	 * the graph will be correct in these cases */
 	log_changes_view = GTK_WIDGET (gtk_builder_get_object (data->bxml, "log_changes_view"));
+	log_branch_combo_model = GTK_TREE_MODEL (gtk_builder_get_object (data->bxml, 
+	                                                                 "log_branch_combo_model"));
+	log_branch_combo = GTK_WIDGET (gtk_builder_get_object (data->bxml,
+	                                                       "log_branch_combo"));
 	graph_column = gtk_tree_view_get_column (GTK_TREE_VIEW (log_changes_view),
 											 1);
+
+	gtk_combo_box_get_active_iter (GTK_COMBO_BOX (log_branch_combo), &iter);
+	gtk_tree_model_get (log_branch_combo_model, &iter, 1, &branch, -1);
 	
 	if (g_hash_table_size (data->filters) > 0 || path)
 		gtk_tree_view_column_set_visible (graph_column, FALSE);
@@ -295,7 +306,7 @@ on_ref_command_finished (AnjutaCommand *command, guint return_code,
 	
 	data->refs = git_ref_command_get_refs (GIT_REF_COMMAND (command));
 	log_command = git_log_command_new (data->plugin->project_root_directory,
-									   relative_path,
+									   branch, relative_path,
 									   author, grep, since_date, until_date,
 									   since_commit, until_commit);
 	
@@ -792,11 +803,117 @@ setup_filters (LogData *data)
 					  data);
 }
 
+static void
+on_log_list_branch_command_data_arrived (AnjutaCommand *command,
+                                         GtkBuilder *bxml)
+{
+	GtkListStore *log_branch_combo_model;
+	GtkComboBox *log_branch_combo;
+	GHashTable *branches_table;
+	GQueue *output_queue;
+	GitBranch *branch;
+	GtkTreeIter iter;
+	gchar *name;
+	
+	log_branch_combo_model = GTK_LIST_STORE (gtk_builder_get_object (bxml, 
+	                                                                 "log_branch_combo_model"));
+	log_branch_combo = GTK_COMBO_BOX (gtk_builder_get_object (bxml,
+	                                                          "log_branch_combo"));
+	branches_table = g_object_get_data (G_OBJECT (log_branch_combo), 
+	                                    "branches-table");
+	output_queue = git_branch_list_command_get_output (GIT_BRANCH_LIST_COMMAND (command));
+
+	while (g_queue_peek_head (output_queue))
+	{
+		branch = g_queue_pop_head (output_queue);
+		name = git_branch_get_name (branch);
+
+		gtk_list_store_append (log_branch_combo_model, &iter);
+		
+		if (git_branch_is_active (branch))
+		{
+			gtk_list_store_set (log_branch_combo_model, &iter, 0, 
+			                    GTK_STOCK_APPLY, -1);
+			gtk_combo_box_set_active_iter (log_branch_combo, &iter);
+		}
+		
+		gtk_list_store_set (log_branch_combo_model, &iter, 1, name, -1);
+		g_hash_table_insert (branches_table, g_strdup (name), 
+		                     g_memdup (&iter, sizeof (GtkTreeIter)));
+
+		g_object_unref (branch);
+		g_free (name);
+	}
+}
+
+static void
+on_log_list_branch_command_finished (AnjutaCommand *command, guint return_code,
+                                     GtkBuilder *bxml)
+{
+	GtkComboBox *log_branch_combo;
+	GHashTable *branches_table;
+	gchar *selected_branch;
+	GtkTreeIter *iter;
+
+	log_branch_combo = GTK_COMBO_BOX (gtk_builder_get_object (bxml,
+	                                                          "log_branch_combo"));
+	branches_table = g_object_get_data (G_OBJECT (log_branch_combo),
+	                                    "branches-table");
+	selected_branch = g_object_get_data (G_OBJECT (log_branch_combo),
+	                                     "selected-branch");
+
+	if (selected_branch)
+	{	
+		if (g_hash_table_lookup_extended (branches_table, selected_branch, NULL,
+		                                  (gpointer *) &iter))
+		{
+			gtk_combo_box_set_active_iter (log_branch_combo, iter);
+		}
+	}
+
+	g_object_set_data (G_OBJECT (log_branch_combo), "being-refreshed",
+	                   GINT_TO_POINTER (FALSE));
+
+	g_object_unref (command);
+	
+}
+
+static void
+on_log_branch_combo_changed (GtkComboBox *combo_box, gpointer user_data)
+{
+	GtkTreeModel *log_branch_combo_model;
+	gchar *branch;
+	GtkTreeIter iter;
+
+	log_branch_combo_model = gtk_combo_box_get_model (combo_box);
+
+	if (gtk_combo_box_get_active_iter (combo_box, &iter))
+	{
+		gtk_tree_model_get (log_branch_combo_model, &iter, 1, &branch, -1);
+
+		g_object_set_data_full (G_OBJECT (combo_box), "selected-branch", 
+		                        branch, (GDestroyNotify) g_free);
+	}
+}
+
+static void 
+on_log_refresh_monitor_changed (GFileMonitor *file_monitor, GFile *file,
+								GFile *other_file, GFileMonitorEvent event_type,
+								Git *plugin)
+{
+	if (event_type == G_FILE_MONITOR_EVENT_CREATED ||
+	    event_type == G_FILE_MONITOR_EVENT_DELETED)
+	{
+		git_log_refresh_branches (plugin);
+	}
+}
+
+
 GtkWidget *
 git_log_window_create (Git *plugin)
 {
 	LogData *data;
-	gchar *objects[] = {"log_window", NULL};
+	gchar *objects[] = {"log_window", "log_branch_combo_model", NULL};
 	GError *error;
 	GtkWidget *log_window;
 	GtkWidget *log_vbox;
@@ -806,6 +923,7 @@ git_log_window_create (Git *plugin)
 	GtkWidget *log_whole_project_check;
 	GtkWidget *log_path_entry;
 	GtkWidget *log_path_entry_hbox;
+	GtkWidget *log_branch_combo;
 	GtkTreeSelection *selection;
 	
 	data = g_new0 (LogData, 1);
@@ -837,6 +955,8 @@ git_log_window_create (Git *plugin)
 	                                                     "log_path_entry"));
 	log_path_entry_hbox = GTK_WIDGET (gtk_builder_get_object (data->bxml,
 	                                                          "log_path_entry_hbox"));
+	log_branch_combo = GTK_WIDGET (gtk_builder_get_object (data->bxml,
+	                                                       "log_branch_combo"));
 	
 	g_object_set_data (G_OBJECT (log_vbox), "log-data", data);
 	
@@ -864,6 +984,10 @@ git_log_window_create (Git *plugin)
 	                  
 	g_signal_connect (G_OBJECT (log_whole_project_check), "toggled",
 					  G_CALLBACK (on_git_whole_project_toggled), plugin);
+
+	g_signal_connect (G_OBJECT (log_branch_combo), "changed",
+	                  G_CALLBACK (on_log_branch_combo_changed),
+	                  NULL);
 	
 	data->list_store = gtk_list_store_new (NUM_COLS,
 										   G_TYPE_OBJECT);
@@ -967,3 +1091,88 @@ git_log_get_path (Git *plugin)
 	
 	return gtk_editable_get_chars (GTK_EDITABLE (log_path_entry), 0, -1);
 }
+
+GFileMonitor *
+git_log_setup_refresh_monitor (Git *plugin)
+{
+	gchar *git_ref_path;
+	GFile *git_ref_file;
+	GFileMonitor *git_ref_monitor;
+
+	git_ref_path = g_strjoin (G_DIR_SEPARATOR_S,
+	                          plugin->project_root_directory,
+	                          ".git",
+	                          "refs",
+	                          "heads",
+	                          NULL);
+
+	git_ref_file = g_file_new_for_path (git_ref_path);
+	git_ref_monitor = g_file_monitor_directory (git_ref_file, 0, NULL, NULL);
+
+	g_file_monitor_set_rate_limit (git_ref_monitor, 1000);
+
+	
+
+	g_signal_connect (G_OBJECT (git_ref_monitor), "changed",
+	                  G_CALLBACK (on_log_refresh_monitor_changed),
+	                  plugin);
+
+	g_free (git_ref_path);
+	g_object_unref (git_ref_file);
+
+	return git_ref_monitor;
+}
+
+void
+git_log_refresh_branches (Git *plugin)
+{
+	LogData *data;
+	GtkWidget *log_branch_combo;
+	gboolean being_refreshed;
+	GtkListStore *log_branch_combo_model;
+	GHashTable *branches_table;
+	GitBranchListCommand *branch_list_command;
+
+	data = g_object_get_data (G_OBJECT (plugin->log_viewer), "log-data");
+	log_branch_combo = GTK_WIDGET (gtk_builder_get_object (data->bxml,
+	                                                       "log_branch_combo"));
+	/* Don't refresh if another refresh is already in progress. The file monitor
+	 * may trigger more than one concurrent refresh, which would populate the  
+	 * combo box several times. The command-finished handler will set the 
+	 * being-refreshed  flag to FALSE when this refresh finishes,  
+	 * allowing the next refresh to go forward. */
+	being_refreshed = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (log_branch_combo),
+	                                                      "being-refreshed"));
+
+	if (!being_refreshed)
+	{
+		log_branch_combo_model = GTK_LIST_STORE (gtk_combo_box_get_model (GTK_COMBO_BOX (log_branch_combo)));
+		branches_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, 
+		                                        g_free);
+		branch_list_command = git_branch_list_command_new (plugin->project_root_directory,
+		                                                   GIT_BRANCH_TYPE_ALL);
+
+		gtk_list_store_clear (log_branch_combo_model);
+
+		/* The branches table keeps track of branch names and iters in the combo
+		 * model, so that the branch that was selected before we refreshed can be
+		 * selected again automatically. If that branch doesn't exist, then
+		 * the currently active branch will be selected. */
+		g_object_set_data_full (G_OBJECT (log_branch_combo), "branches-table",
+		                        branches_table, (GDestroyNotify) g_hash_table_destroy);
+
+		g_signal_connect (G_OBJECT (branch_list_command), "data-arrived",
+		                  G_CALLBACK (on_log_list_branch_command_data_arrived),
+		                  data->bxml);
+
+		g_signal_connect (G_OBJECT (branch_list_command), "command-finished",
+		                  G_CALLBACK (on_log_list_branch_command_finished),
+		                  data->bxml);
+
+		g_object_set_data (G_OBJECT (log_branch_combo), "being-refreshed",
+		                   GINT_TO_POINTER (TRUE));
+
+		anjuta_command_start (ANJUTA_COMMAND (branch_list_command));
+	}
+	
+}
diff --git a/plugins/git/git-log-dialog.h b/plugins/git/git-log-dialog.h
index 4c2bfe3..054b555 100644
--- a/plugins/git/git-log-dialog.h
+++ b/plugins/git/git-log-dialog.h
@@ -38,5 +38,7 @@ GtkWidget *git_log_window_create (Git *plugin);
 void git_log_window_clear (Git *plugin);
 GitRevision *git_log_get_selected_revision (Git *plugin);
 gchar *git_log_get_path (Git *plugin);
+GFileMonitor *git_log_setup_refresh_monitor (Git *plugin);
+void git_log_refresh_branches (Git *plugin);
 
 #endif
diff --git a/plugins/git/plugin.c b/plugins/git/plugin.c
index e256eb2..328ac75 100644
--- a/plugins/git/plugin.c
+++ b/plugins/git/plugin.c
@@ -530,6 +530,8 @@ on_project_root_added (AnjutaPlugin *plugin, const gchar *name,
 	g_free (project_root_uri);
 	
 	git_plugin->bisect_file_monitor = bisect_menus_init (git_plugin);
+	git_plugin->log_refresh_monitor = git_log_setup_refresh_monitor (git_plugin);
+	git_log_refresh_branches (git_plugin);
 }
 
 static void
@@ -561,6 +563,7 @@ on_project_root_removed (AnjutaPlugin *plugin, const gchar *name,
 	git_log_window_clear (git_plugin);
 	
 	g_file_monitor_cancel (git_plugin->bisect_file_monitor);
+	g_file_monitor_cancel (git_plugin->log_refresh_monitor);
 	g_object_unref (git_plugin->bisect_file_monitor);
 }
 
diff --git a/plugins/git/plugin.h b/plugins/git/plugin.h
index 7df0a46..e2f406c 100644
--- a/plugins/git/plugin.h
+++ b/plugins/git/plugin.h
@@ -65,6 +65,7 @@ struct _Git
 	
 	/* File monitors */
 	GFileMonitor *bisect_file_monitor;
+	GFileMonitor *log_refresh_monitor;
 };
 
 struct _GitClass



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