1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4 * Copyright (C) James Liggett 2010 <jrliggett@cox.net>
6 * git-shell-test is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * git-shell-test is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "git-branches-pane.h"
30 static GtkTargetEntry drag_targets
[] =
39 struct _GitBranchesPanePriv
42 GHashTable
*selected_local_branches
;
43 GHashTable
*selected_remote_branches
;
47 G_DEFINE_TYPE (GitBranchesPane
, git_branches_pane
, GIT_TYPE_PANE
);
49 /* The local branch command is started first, usually automatically. Then the
50 * remote branches are listed. We need to have both in the same model, so
51 * the model isn't restored until the remote list command fisishes. */
54 on_local_branch_list_command_started (AnjutaCommand
*command
,
55 GitBranchesPane
*self
)
57 GtkTreeView
*branches_view
;
58 GtkListStore
*branches_list_model
;
60 branches_view
= GTK_TREE_VIEW (gtk_builder_get_object (self
->priv
->builder
,
62 branches_list_model
= GTK_LIST_STORE (gtk_builder_get_object (self
->priv
->builder
,
63 "branches_list_model"));
66 gtk_tree_view_set_model (branches_view
, NULL
);
67 gtk_list_store_clear (branches_list_model
);
68 g_hash_table_remove_all (self
->priv
->selected_local_branches
);
69 g_hash_table_remove_all (self
->priv
->selected_remote_branches
);
73 on_remote_branch_list_command_finished (AnjutaCommand
*command
,
75 GitBranchesPane
*self
)
77 GtkTreeView
*branches_view
;
78 GtkListStore
*branches_list_model
;
80 branches_view
= GTK_TREE_VIEW (gtk_builder_get_object (self
->priv
->builder
,
82 branches_list_model
= GTK_LIST_STORE (gtk_builder_get_object (self
->priv
->builder
,
83 "branches_list_model"));
85 gtk_tree_view_set_model (branches_view
,
86 GTK_TREE_MODEL (branches_list_model
));
90 on_local_branch_list_command_data_arrived (AnjutaCommand
*command
,
91 GitBranchesPane
*self
)
93 GtkListStore
*branches_list_model
;
94 GList
*current_branch
;
100 branches_list_model
= GTK_LIST_STORE (gtk_builder_get_object (self
->priv
->builder
,
101 "branches_list_model"));
102 current_branch
= git_branch_list_command_get_output (GIT_BRANCH_LIST_COMMAND (command
));
104 while (current_branch
)
106 branch
= current_branch
->data
;
107 name
= git_branch_get_name (branch
);
108 active
= git_branch_is_active (branch
);
110 gtk_list_store_append (branches_list_model
, &iter
);
111 gtk_list_store_set (branches_list_model
, &iter
,
120 current_branch
= g_list_next (current_branch
);
125 on_remote_branch_list_command_data_arrived (AnjutaCommand
*command
,
126 GitBranchesPane
*self
)
128 GtkListStore
*branches_list_model
;
129 GList
*current_branch
;
135 branches_list_model
= GTK_LIST_STORE (gtk_builder_get_object (self
->priv
->builder
,
136 "branches_list_model"));
137 current_branch
= git_branch_list_command_get_output (GIT_BRANCH_LIST_COMMAND (command
));
139 while (current_branch
)
141 branch
= current_branch
->data
;
142 name
= git_branch_get_name (branch
);
143 active
= git_branch_is_active (branch
);
145 /* Make sure these entries are treated as remotes */
147 gtk_list_store_append (branches_list_model
, &iter
);
148 gtk_list_store_set (branches_list_model
, &iter
,
157 current_branch
= g_list_next (current_branch
);
162 selected_column_data_func (GtkTreeViewColumn
*column
, GtkCellRenderer
*renderer
,
163 GtkTreeModel
*model
, GtkTreeIter
*iter
,
164 GitBranchesPane
*self
)
169 gtk_tree_model_get (model
, iter
, COL_SELECTED
, &selected
, COL_ACTIVE
,
172 gtk_cell_renderer_toggle_set_active (GTK_CELL_RENDERER_TOGGLE (renderer
),
174 gtk_cell_renderer_toggle_set_activatable (GTK_CELL_RENDERER_TOGGLE (renderer
),
179 active_icon_data_func (GtkTreeViewColumn
*column
, GtkCellRenderer
*renderer
,
180 GtkTreeModel
*model
, GtkTreeIter
*iter
,
181 GitBranchesPane
*self
)
185 gtk_tree_model_get (model
, iter
, COL_ACTIVE
, &active
, -1);
188 g_object_set (renderer
, "stock-id", GTK_STOCK_APPLY
, NULL
);
190 g_object_set (renderer
, "stock-id", NULL
, NULL
);
194 on_branch_selected_renderer_toggled (GtkCellRendererToggle
*renderer
,
195 gchar
*path
, GitBranchesPane
*self
)
197 GtkTreeModel
*branches_list_model
;
202 GHashTable
*selection_table
;
204 branches_list_model
= GTK_TREE_MODEL (gtk_builder_get_object (self
->priv
->builder
,
205 "branches_list_model"));
207 gtk_tree_model_get_iter_from_string (branches_list_model
, &iter
, path
);
208 gtk_tree_model_get (branches_list_model
, &iter
,
209 COL_SELECTED
, &selected
,
214 selected
= !selected
;
217 selection_table
= self
->priv
->selected_remote_branches
;
219 selection_table
= self
->priv
->selected_local_branches
;
221 /* The selection tables are hash sets of each type of selected branch
222 * (local or remote.) The hash table takes ownership of the name string. */
224 g_hash_table_insert (selection_table
, name
, NULL
);
226 g_hash_table_remove (selection_table
, name
);
228 gtk_list_store_set (GTK_LIST_STORE (branches_list_model
), &iter
, 0, selected
,
233 on_branches_list_view_drag_data_get (GtkWidget
*branches_list_view
,
234 GdkDragContext
*drag_context
,
235 GtkSelectionData
*data
,
236 guint info
, guint time
,
237 GitBranchesPane
*self
)
239 GtkTreeSelection
*selection
;
241 GtkTreeModel
*branches_list_model
;
244 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (branches_list_view
));
246 if (gtk_tree_selection_count_selected_rows (selection
) > 0)
248 gtk_tree_selection_get_selected (selection
, &branches_list_model
,
251 gtk_tree_model_get (branches_list_model
, &iter
, COL_NAME
, &name
, -1);
253 gtk_selection_data_set_text (data
, name
, -1);
260 selected_branches_table_foreach (gchar
*name
, gpointer value
,
263 *list
= g_list_append (*list
, g_strdup (name
));
267 git_branches_pane_init (GitBranchesPane
*self
)
269 gchar
*objects
[] = {"branches_pane",
270 "branches_list_model",
272 GError
*error
= NULL
;
273 GtkTreeView
*branches_view
;
274 GtkTreeViewColumn
*branch_selected_column
;
275 GtkCellRenderer
*branch_selected_renderer
;
276 GtkTreeViewColumn
*branch_name_column
;
277 GtkCellRenderer
*branch_active_icon_renderer
;
279 self
->priv
= g_new0 (GitBranchesPanePriv
, 1);
280 self
->priv
->builder
= gtk_builder_new ();
281 self
->priv
->selected_local_branches
= g_hash_table_new_full (g_str_hash
,
285 self
->priv
->selected_remote_branches
= g_hash_table_new_full (g_str_hash
,
291 if (!gtk_builder_add_objects_from_file (self
->priv
->builder
, BUILDER_FILE
,
295 g_warning ("Couldn't load builder file: %s", error
->message
);
296 g_error_free (error
);
299 branches_view
= GTK_TREE_VIEW (gtk_builder_get_object (self
->priv
->builder
,
301 branch_selected_column
= GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (self
->priv
->builder
,
302 "branch_selected_column"));
303 branch_selected_renderer
= GTK_CELL_RENDERER (gtk_builder_get_object (self
->priv
->builder
,
304 "branch_selected_renderer"));
305 branch_name_column
= GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (self
->priv
->builder
,
306 "branch_name_column"));
307 branch_active_icon_renderer
= GTK_CELL_RENDERER (gtk_builder_get_object (self
->priv
->builder
,
308 "branch_active_icon_renderer"));
311 gtk_tree_view_enable_model_drag_source (branches_view
,
314 G_N_ELEMENTS (drag_targets
),
317 g_signal_connect (G_OBJECT (branches_view
), "drag-data-get",
318 G_CALLBACK (on_branches_list_view_drag_data_get
),
321 gtk_tree_view_column_set_cell_data_func (branch_selected_column
,
322 branch_selected_renderer
,
323 (GtkTreeCellDataFunc
) selected_column_data_func
,
327 gtk_tree_view_column_set_cell_data_func (branch_name_column
,
328 branch_active_icon_renderer
,
329 (GtkTreeCellDataFunc
) active_icon_data_func
,
333 g_signal_connect (G_OBJECT (branch_selected_renderer
), "toggled",
334 G_CALLBACK (on_branch_selected_renderer_toggled
),
339 git_branches_pane_finalize (GObject
*object
)
341 GitBranchesPane
*self
;
343 self
= GIT_BRANCHES_PANE (object
);
345 g_object_unref (self
->priv
->builder
);
346 g_hash_table_destroy (self
->priv
->selected_local_branches
);
347 g_hash_table_destroy (self
->priv
->selected_remote_branches
);
350 G_OBJECT_CLASS (git_branches_pane_parent_class
)->finalize (object
);
354 git_branches_pane_get_widget (AnjutaDockPane
*pane
)
356 GitBranchesPane
*self
;
358 self
= GIT_BRANCHES_PANE (pane
);
360 return GTK_WIDGET (gtk_builder_get_object (self
->priv
->builder
,
365 git_branches_pane_refresh (AnjutaDockPane
*pane
)
367 /* TODO: Add private function implementation here */
371 git_branches_pane_class_init (GitBranchesPaneClass
*klass
)
373 GObjectClass
* object_class
= G_OBJECT_CLASS (klass
);
374 AnjutaDockPaneClass
*pane_class
= ANJUTA_DOCK_PANE_CLASS (klass
);
376 object_class
->finalize
= git_branches_pane_finalize
;
377 pane_class
->get_widget
= git_branches_pane_get_widget
;
378 pane_class
->refresh
= git_branches_pane_refresh
;
383 git_branches_pane_new (Git
*plugin
)
385 GitBranchesPane
*self
;
387 self
= g_object_new (GIT_TYPE_BRANCHES_PANE
, "plugin", plugin
, NULL
);
389 g_signal_connect (G_OBJECT (plugin
->local_branch_list_command
),
391 G_CALLBACK (on_local_branch_list_command_started
),
394 g_signal_connect (G_OBJECT (plugin
->remote_branch_list_command
),
396 G_CALLBACK (on_remote_branch_list_command_finished
),
399 g_signal_connect (G_OBJECT (plugin
->local_branch_list_command
),
401 G_CALLBACK (on_local_branch_list_command_data_arrived
),
404 g_signal_connect (G_OBJECT (plugin
->remote_branch_list_command
),
406 G_CALLBACK (on_remote_branch_list_command_data_arrived
),
409 return ANJUTA_DOCK_PANE (self
);
413 git_branches_pane_get_selected_local_branches (GitBranchesPane
*self
)
419 g_hash_table_foreach (self
->priv
->selected_local_branches
,
420 (GHFunc
) selected_branches_table_foreach
,
427 git_branches_pane_get_selected_remote_branches (GitBranchesPane
*self
)
433 g_hash_table_foreach (self
->priv
->selected_remote_branches
,
434 (GHFunc
) selected_branches_table_foreach
,
441 git_branches_pane_count_selected_items (GitBranchesPane
*self
)
443 return (g_hash_table_size (self
->priv
->selected_local_branches
)) +
444 (g_hash_table_size (self
->priv
->selected_remote_branches
));
448 git_branches_pane_get_selected_branch (GitBranchesPane
*self
)
450 gchar
*selected_branch
;
451 GtkTreeView
*branches_view
;
452 GtkTreeSelection
*selection
;
453 GtkTreeModel
*branches_list_model
;
456 selected_branch
= NULL
;
457 branches_view
= GTK_TREE_VIEW (gtk_builder_get_object (self
->priv
->builder
,
459 selection
= gtk_tree_view_get_selection (branches_view
);
461 if (gtk_tree_selection_count_selected_rows (selection
) > 0)
463 gtk_tree_selection_get_selected (selection
, &branches_list_model
,
466 gtk_tree_model_get (branches_list_model
, &iter
, COL_NAME
,
467 &selected_branch
, -1);
470 return selected_branch
;
474 clear_branch_selections (GtkTreeModel
*model
, GtkTreePath
*path
,
475 GtkTreeIter
*iter
, gpointer data
)
477 gtk_list_store_set (GTK_LIST_STORE (model
), iter
, COL_SELECTED
, FALSE
, -1);
483 git_branches_pane_set_select_column_visible (GitBranchesPane
*self
,
486 GtkTreeViewColumn
*branch_selected_column
;
487 GtkTreeModel
*branches_list_model
;
489 branch_selected_column
= GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (self
->priv
->builder
,
490 "branch_selected_column"));
492 gtk_tree_view_column_set_visible (branch_selected_column
, visible
);
494 /* Clear branch selections when the column becomes invisible again, because
495 * selections have no meaning once an operation that needs these selections
496 * has either been completed or cancelled */
499 branches_list_model
= GTK_TREE_MODEL (gtk_builder_get_object (self
->priv
->builder
,
500 "branches_list_model"));
502 gtk_tree_model_foreach (branches_list_model
,
503 (GtkTreeModelForeachFunc
) clear_branch_selections
,
506 g_hash_table_remove_all (self
->priv
->selected_local_branches
);
507 g_hash_table_remove_all (self
->priv
->selected_remote_branches
);