Updated Spanish translation
[anjuta.git] / plugins / git / git-branches-pane.c
blob87b4759dd0365e7de7a8079739fd6811f93207cf
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * git-shell-test
4 * Copyright (C) James Liggett 2010 <jrliggett@cox.net>
5 *
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"
22 enum
24 COL_SELECTED,
25 COL_ACTIVE,
26 COL_REMOTE,
27 COL_NAME
30 static GtkTargetEntry drag_targets[] =
33 "STRING",
39 struct _GitBranchesPanePriv
41 GtkBuilder *builder;
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. */
53 static void
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,
61 "branches_view"));
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);
72 static void
73 on_remote_branch_list_command_finished (AnjutaCommand *command,
74 guint return_code,
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,
81 "branches_view"));
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));
89 static void
90 on_local_branch_list_command_data_arrived (AnjutaCommand *command,
91 GitBranchesPane *self)
93 GtkListStore *branches_list_model;
94 GList *current_branch;
95 GitBranch *branch;
96 gboolean active;
97 gchar *name;
98 GtkTreeIter iter;
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,
112 COL_SELECTED, FALSE,
113 COL_ACTIVE, active,
114 COL_REMOTE, FALSE,
115 COL_NAME, name,
116 -1);
118 g_free (name);
120 current_branch = g_list_next (current_branch);
124 static void
125 on_remote_branch_list_command_data_arrived (AnjutaCommand *command,
126 GitBranchesPane *self)
128 GtkListStore *branches_list_model;
129 GList *current_branch;
130 GitBranch *branch;
131 gboolean active;
132 gchar *name;
133 GtkTreeIter iter;
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,
149 COL_SELECTED, FALSE,
150 COL_ACTIVE, active,
151 COL_REMOTE, TRUE,
152 COL_NAME, name,
153 -1);
155 g_free (name);
157 current_branch = g_list_next (current_branch);
161 static void
162 selected_column_data_func (GtkTreeViewColumn *column, GtkCellRenderer *renderer,
163 GtkTreeModel *model, GtkTreeIter *iter,
164 GitBranchesPane *self)
166 gboolean selected;
167 gboolean active;
169 gtk_tree_model_get (model, iter, COL_SELECTED, &selected, COL_ACTIVE,
170 &active, -1);
172 gtk_cell_renderer_toggle_set_active (GTK_CELL_RENDERER_TOGGLE (renderer),
173 selected);
174 gtk_cell_renderer_toggle_set_activatable (GTK_CELL_RENDERER_TOGGLE (renderer),
175 !active);
178 static void
179 active_icon_data_func (GtkTreeViewColumn *column, GtkCellRenderer *renderer,
180 GtkTreeModel *model, GtkTreeIter *iter,
181 GitBranchesPane *self)
183 gboolean active;
185 gtk_tree_model_get (model, iter, COL_ACTIVE, &active, -1);
187 if (active)
188 g_object_set (renderer, "stock-id", GTK_STOCK_APPLY, NULL);
189 else
190 g_object_set (renderer, "stock-id", NULL, NULL);
193 static void
194 on_branch_selected_renderer_toggled (GtkCellRendererToggle *renderer,
195 gchar *path, GitBranchesPane *self)
197 GtkTreeModel *branches_list_model;
198 GtkTreeIter iter;
199 gboolean selected;
200 gboolean remote;
201 gchar *name;
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,
210 COL_REMOTE, &remote,
211 COL_NAME, &name,
212 -1);
214 selected = !selected;
216 if (remote)
217 selection_table = self->priv->selected_remote_branches;
218 else
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. */
223 if (selected)
224 g_hash_table_insert (selection_table, name, NULL);
225 else
226 g_hash_table_remove (selection_table, name);
228 gtk_list_store_set (GTK_LIST_STORE (branches_list_model), &iter, 0, selected,
229 -1);
232 static void
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;
240 GtkTreeIter iter;
241 GtkTreeModel *branches_list_model;
242 gchar *name;
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,
249 &iter);
251 gtk_tree_model_get (branches_list_model, &iter, COL_NAME, &name, -1);
253 gtk_selection_data_set_text (data, name, -1);
255 g_free (name);
259 static void
260 selected_branches_table_foreach (gchar *name, gpointer value,
261 GList **list)
263 *list = g_list_append (*list, g_strdup (name));
266 static void
267 on_branches_view_row_activated (GtkTreeView *branches_view, GtkTreePath *path,
268 GtkTreeViewColumn *column, GitBranchesPane *self)
270 GtkTreeModel *model;
271 GtkTreeIter iter;
272 gchar *branch;
273 Git *plugin;
274 GitBranchCheckoutCommand *checkout_command;
276 model = gtk_tree_view_get_model (branches_view);
277 gtk_tree_model_get_iter (model, &iter, path);
279 gtk_tree_model_get (model, &iter, COL_NAME, &branch, -1);
281 plugin = ANJUTA_PLUGIN_GIT (anjuta_dock_pane_get_plugin (ANJUTA_DOCK_PANE (self)));
282 checkout_command = git_branch_checkout_command_new (plugin->project_root_directory,
283 branch);
285 g_signal_connect (G_OBJECT (checkout_command), "command-finished",
286 G_CALLBACK (git_pane_report_errors),
287 plugin);
289 g_signal_connect (G_OBJECT (checkout_command), "command-finished",
290 G_CALLBACK (g_object_unref),
291 NULL);
293 g_free (branch);
295 anjuta_command_start (ANJUTA_COMMAND (checkout_command));
298 static gboolean
299 on_branches_view_button_press_event (GtkWidget *branches_view,
300 GdkEventButton *event,
301 GitBranchesPane *self)
303 GtkTreeSelection *selection;
304 AnjutaPlugin *plugin;
305 AnjutaUI *ui;
306 GtkMenu *menu;
308 if (event->type == GDK_BUTTON_PRESS && event->button == 3)
310 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (branches_view));
312 if (gtk_tree_selection_count_selected_rows (selection) > 0)
314 plugin = anjuta_dock_pane_get_plugin (ANJUTA_DOCK_PANE (self));
315 ui = anjuta_shell_get_ui (plugin->shell, NULL);
316 menu = GTK_MENU (gtk_ui_manager_get_widget (GTK_UI_MANAGER (ui),
317 "/GitBranchPopup"));
319 gtk_menu_popup (menu, NULL, NULL, NULL, NULL, event->button,
320 event->time);
324 return FALSE;
327 static void
328 git_branches_pane_init (GitBranchesPane *self)
330 gchar *objects[] = {"branches_pane",
331 "branches_list_model",
332 NULL};
333 GError *error = NULL;
334 GtkTreeView *branches_view;
335 GtkTreeViewColumn *branch_selected_column;
336 GtkCellRenderer *branch_selected_renderer;
337 GtkTreeViewColumn *branch_name_column;
338 GtkCellRenderer *branch_active_icon_renderer;
340 self->priv = g_new0 (GitBranchesPanePriv, 1);
341 self->priv->builder = gtk_builder_new ();
342 self->priv->selected_local_branches = g_hash_table_new_full (g_str_hash,
343 g_str_equal,
344 g_free,
345 NULL);
346 self->priv->selected_remote_branches = g_hash_table_new_full (g_str_hash,
347 g_str_equal,
348 g_free,
349 NULL);
352 if (!gtk_builder_add_objects_from_file (self->priv->builder, BUILDER_FILE,
353 objects,
354 &error))
356 g_warning ("Couldn't load builder file: %s", error->message);
357 g_error_free (error);
360 branches_view = GTK_TREE_VIEW (gtk_builder_get_object (self->priv->builder,
361 "branches_view"));
362 branch_selected_column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (self->priv->builder,
363 "branch_selected_column"));
364 branch_selected_renderer = GTK_CELL_RENDERER (gtk_builder_get_object (self->priv->builder,
365 "branch_selected_renderer"));
366 branch_name_column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (self->priv->builder,
367 "branch_name_column"));
368 branch_active_icon_renderer = GTK_CELL_RENDERER (gtk_builder_get_object (self->priv->builder,
369 "branch_active_icon_renderer"));
371 /* DND */
372 gtk_tree_view_enable_model_drag_source (branches_view,
373 GDK_BUTTON1_MASK,
374 drag_targets,
375 G_N_ELEMENTS (drag_targets),
376 GDK_ACTION_COPY);
378 g_signal_connect (G_OBJECT (branches_view), "drag-data-get",
379 G_CALLBACK (on_branches_list_view_drag_data_get),
380 self);
382 gtk_tree_view_column_set_cell_data_func (branch_selected_column,
383 branch_selected_renderer,
384 (GtkTreeCellDataFunc) selected_column_data_func,
385 self,
386 NULL);
388 gtk_tree_view_column_set_cell_data_func (branch_name_column,
389 branch_active_icon_renderer,
390 (GtkTreeCellDataFunc) active_icon_data_func,
391 self,
392 NULL);
394 g_signal_connect (G_OBJECT (branch_selected_renderer), "toggled",
395 G_CALLBACK (on_branch_selected_renderer_toggled),
396 self);
398 /* Switch branches on double-click */
399 g_signal_connect (G_OBJECT (branches_view), "row-activated",
400 G_CALLBACK (on_branches_view_row_activated),
401 self);
403 /* Pop-up menu */
404 g_signal_connect (G_OBJECT (branches_view), "button-press-event",
405 G_CALLBACK (on_branches_view_button_press_event),
406 self);
409 static void
410 git_branches_pane_finalize (GObject *object)
412 GitBranchesPane *self;
414 self = GIT_BRANCHES_PANE (object);
416 g_object_unref (self->priv->builder);
417 g_hash_table_destroy (self->priv->selected_local_branches);
418 g_hash_table_destroy (self->priv->selected_remote_branches);
419 g_free (self->priv);
421 G_OBJECT_CLASS (git_branches_pane_parent_class)->finalize (object);
424 static GtkWidget *
425 git_branches_pane_get_widget (AnjutaDockPane *pane)
427 GitBranchesPane *self;
429 self = GIT_BRANCHES_PANE (pane);
431 return GTK_WIDGET (gtk_builder_get_object (self->priv->builder,
432 "branches_pane"));
435 static void
436 git_branches_pane_refresh (AnjutaDockPane *pane)
438 /* TODO: Add private function implementation here */
441 static void
442 git_branches_pane_class_init (GitBranchesPaneClass *klass)
444 GObjectClass* object_class = G_OBJECT_CLASS (klass);
445 AnjutaDockPaneClass *pane_class = ANJUTA_DOCK_PANE_CLASS (klass);
447 object_class->finalize = git_branches_pane_finalize;
448 pane_class->get_widget = git_branches_pane_get_widget;
449 pane_class->refresh = git_branches_pane_refresh;
453 AnjutaDockPane *
454 git_branches_pane_new (Git *plugin)
456 GitBranchesPane *self;
458 self = g_object_new (GIT_TYPE_BRANCHES_PANE, "plugin", plugin, NULL);
460 g_signal_connect (G_OBJECT (plugin->local_branch_list_command),
461 "command-started",
462 G_CALLBACK (on_local_branch_list_command_started),
463 self);
465 g_signal_connect (G_OBJECT (plugin->remote_branch_list_command),
466 "command-finished",
467 G_CALLBACK (on_remote_branch_list_command_finished),
468 self);
470 g_signal_connect (G_OBJECT (plugin->local_branch_list_command),
471 "data-arrived",
472 G_CALLBACK (on_local_branch_list_command_data_arrived),
473 self);
475 g_signal_connect (G_OBJECT (plugin->remote_branch_list_command),
476 "data-arrived",
477 G_CALLBACK (on_remote_branch_list_command_data_arrived),
478 self);
480 return ANJUTA_DOCK_PANE (self);
483 GList *
484 git_branches_pane_get_selected_local_branches (GitBranchesPane *self)
486 GList *list;
488 list = NULL;
490 g_hash_table_foreach (self->priv->selected_local_branches,
491 (GHFunc) selected_branches_table_foreach,
492 &list);
494 return list;
497 GList *
498 git_branches_pane_get_selected_remote_branches (GitBranchesPane *self)
500 GList *list;
502 list = NULL;
504 g_hash_table_foreach (self->priv->selected_remote_branches,
505 (GHFunc) selected_branches_table_foreach,
506 &list);
508 return list;
511 gsize
512 git_branches_pane_count_selected_items (GitBranchesPane *self)
514 return (g_hash_table_size (self->priv->selected_local_branches)) +
515 (g_hash_table_size (self->priv->selected_remote_branches));
518 gchar *
519 git_branches_pane_get_selected_branch (GitBranchesPane *self)
521 gchar *selected_branch;
522 GtkTreeView *branches_view;
523 GtkTreeSelection *selection;
524 GtkTreeModel *branches_list_model;
525 GtkTreeIter iter;
527 selected_branch = NULL;
528 branches_view = GTK_TREE_VIEW (gtk_builder_get_object (self->priv->builder,
529 "branches_view"));
530 selection = gtk_tree_view_get_selection (branches_view);
532 if (gtk_tree_selection_count_selected_rows (selection) > 0)
534 gtk_tree_selection_get_selected (selection, &branches_list_model,
535 &iter);
537 gtk_tree_model_get (branches_list_model, &iter, COL_NAME,
538 &selected_branch, -1);
541 return selected_branch;
544 gboolean
545 git_branches_pane_is_selected_branch_remote (GitBranchesPane *self)
547 gboolean is_remote;
548 GtkTreeView *branches_view;
549 GtkTreeSelection *selection;
550 GtkTreeModel *branches_list_model;
551 GtkTreeIter iter;
553 is_remote = FALSE;
554 branches_view = GTK_TREE_VIEW (gtk_builder_get_object (self->priv->builder,
555 "branches_view"));
556 selection = gtk_tree_view_get_selection (branches_view);
558 if (gtk_tree_selection_count_selected_rows (selection) > 0)
560 gtk_tree_selection_get_selected (selection, &branches_list_model,
561 &iter);
563 gtk_tree_model_get (branches_list_model, &iter, COL_REMOTE,
564 &is_remote, -1);
567 return is_remote;
570 static gboolean
571 clear_branch_selections (GtkTreeModel *model, GtkTreePath *path,
572 GtkTreeIter *iter, gpointer data)
574 gtk_list_store_set (GTK_LIST_STORE (model), iter, COL_SELECTED, FALSE, -1);
576 return FALSE;
579 void
580 git_branches_pane_set_select_column_visible (GitBranchesPane *self,
581 gboolean visible)
583 GtkTreeViewColumn *branch_selected_column;
584 GtkTreeModel *branches_list_model;
586 branch_selected_column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (self->priv->builder,
587 "branch_selected_column"));
589 gtk_tree_view_column_set_visible (branch_selected_column, visible);
591 /* Clear branch selections when the column becomes invisible again, because
592 * selections have no meaning once an operation that needs these selections
593 * has either been completed or cancelled */
594 if (!visible)
596 branches_list_model = GTK_TREE_MODEL (gtk_builder_get_object (self->priv->builder,
597 "branches_list_model"));
599 gtk_tree_model_foreach (branches_list_model,
600 (GtkTreeModelForeachFunc) clear_branch_selections,
601 NULL);
603 g_hash_table_remove_all (self->priv->selected_local_branches);
604 g_hash_table_remove_all (self->priv->selected_remote_branches);