Implement bisecting
[anjuta-git-plugin.git] / plugins / git / plugin.c
blob4d85148d58e2810b614c795409f522814dc8fc9e
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 plugin.c
4 Copyright (C) James Liggett 2008
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301 USA
22 #include "plugin.h"
23 #include "git-diff-dialog.h"
24 #include "git-commit-dialog.h"
25 #include "git-add-dialog.h"
26 #include "git-remove-dialog.h"
27 #include "git-resolve-dialog.h"
28 #include "git-merge-dialog.h"
29 #include "git-switch-dialog.h"
30 #include "git-create-branch-dialog.h"
31 #include "git-delete-branch-dialog.h"
32 #include "git-unstage-dialog.h"
33 #include "git-checkout-files-dialog.h"
34 #include "git-log-dialog.h"
35 #include "git-create-tag-dialog.h"
36 #include "git-reset-dialog.h"
37 #include "git-revert-dialog.h"
38 #include "git-fetch-dialog.h"
39 #include "git-rebase-dialog.h"
40 #include "git-bisect-dialog.h"
42 #define UI_FILE PACKAGE_DATA_DIR"/ui/anjuta-git.ui"
44 static gpointer parent_class;
46 static GtkActionEntry actions_git[] =
49 "ActionMenuGit", /* Action name */
50 NULL, /* Stock icon, if any */
51 N_("_Git"), /* Display label */
52 NULL, /* short-cut */
53 NULL, /* Tooltip */
54 NULL /* action callback */
57 "ActionGitCommit", /* Action name */
58 GTK_STOCK_YES, /* Stock icon, if any */
59 N_("_Commit..."), /* Display label */
60 NULL, /* short-cut */
61 NULL, /* Tooltip */
62 G_CALLBACK (on_menu_git_commit) /* action callback */
65 "ActionGitFetch", /* Action name */
66 GTK_STOCK_CONNECT, /* Stock icon, if any */
67 N_("_Fetch"), /* Display label */
68 NULL, /* short-cut */
69 NULL, /* Tooltip */
70 G_CALLBACK (on_menu_git_fetch) /* action callback */
73 "ActionMenuGitRebase", /* Action name */
74 NULL, /* Stock icon, if any */
75 N_("_Rebase"), /* Display label */
76 NULL, /* short-cut */
77 NULL, /* Tooltip */
78 NULL /* action callback */
81 "ActionGitRebaseStart", /* Action name */
82 NULL, /* Stock icon, if any */
83 N_("_Start..."), /* Display label */
84 NULL, /* short-cut */
85 NULL, /* Tooltip */
86 G_CALLBACK (on_menu_git_rebase_start) /* action callback */
89 "ActionGitRebaseContinue", /* Action name */
90 NULL, /* Stock icon, if any */
91 N_("_Continue"), /* Display label */
92 NULL, /* short-cut */
93 NULL, /* Tooltip */
94 G_CALLBACK (on_menu_git_rebase_continue) /* action callback */
97 "ActionGitRebaseSkip", /* Action name */
98 NULL, /* Stock icon, if any */
99 N_("_Skip"), /* Display label */
100 NULL, /* short-cut */
101 NULL, /* Tooltip */
102 G_CALLBACK (on_menu_git_rebase_skip) /* action callback */
105 "ActionGitRebaseAbort", /* Action name */
106 NULL, /* Stock icon, if any */
107 N_("_Abort"), /* Display label */
108 NULL, /* short-cut */
109 NULL, /* Tooltip */
110 G_CALLBACK (on_menu_git_rebase_abort) /* action callback */
113 "ActionGitUnstageFiles", /* Action name */
114 GTK_STOCK_CANCEL, /* Stock icon, if any */
115 N_("_Unstage files..."), /* Display label */
116 NULL, /* short-cut */
117 NULL, /* Tooltip */
118 G_CALLBACK (on_menu_git_unstage) /* action callback */
121 "ActionGitCheckoutFiles", /* Action name */
122 GTK_STOCK_UNDO, /* Stock icon, if any */
123 N_("_Check out files..."), /* Display label */
124 NULL, /* short-cut */
125 NULL, /* Tooltip */
126 G_CALLBACK (on_menu_git_checkout_files) /* action callback */
129 "ActionGitResolve", /* Action name */
130 GTK_STOCK_PREFERENCES, /* Stock icon, if any */
131 N_("_Resolve conflicts..."), /* Display label */
132 NULL, /* short-cut */
133 NULL, /* Tooltip */
134 G_CALLBACK (on_menu_git_resolve) /* action callback */
137 "ActionGitReset", /* Action name */
138 GTK_STOCK_REFRESH, /* Stock icon, if any */
139 N_("_Reset tree..."), /* Display label */
140 NULL, /* short-cut */
141 NULL, /* Tooltip */
142 G_CALLBACK (on_menu_git_reset) /* action callback */
145 "ActionGitRevert", /* Action name */
146 GTK_STOCK_UNDO, /* Stock icon, if any */
147 N_("_Revert commit..."), /* Display label */
148 NULL, /* short-cut */
149 NULL, /* Tooltip */
150 G_CALLBACK (on_menu_git_revert) /* action callback */
153 "ActionMenuGitBisect", /* Action name */
154 NULL, /* Stock icon, if any */
155 N_("_Bisect"), /* Display label */
156 NULL, /* short-cut */
157 NULL, /* Tooltip */
158 NULL /* action callback */
161 "ActionGitBisectStart", /* Action name */
162 GTK_STOCK_MEDIA_PLAY, /* Stock icon, if any */
163 N_("_Start..."), /* Display label */
164 NULL, /* short-cut */
165 NULL, /* Tooltip */
166 G_CALLBACK (on_menu_git_bisect_start) /* action callback */
169 "ActionGitBisectReset", /* Action name */
170 GTK_STOCK_REFRESH, /* Stock icon, if any */
171 N_("_Reset"), /* Display label */
172 NULL, /* short-cut */
173 NULL, /* Tooltip */
174 G_CALLBACK (on_menu_git_bisect_reset) /* action callback */
177 "ActionGitBisectGood", /* Action name */
178 GTK_STOCK_YES, /* Stock icon, if any */
179 N_("_Good"), /* Display label */
180 NULL, /* short-cut */
181 NULL, /* Tooltip */
182 G_CALLBACK (on_menu_git_bisect_good) /* action callback */
185 "ActionGitBisectBad", /* Action name */
186 GTK_STOCK_NO, /* Stock icon, if any */
187 N_("_Bad"), /* Display label */
188 NULL, /* short-cut */
189 NULL, /* Tooltip */
190 G_CALLBACK (on_menu_git_bisect_bad) /* action callback */
193 "ActionGitLog", /* Action name */
194 GTK_STOCK_ZOOM_100, /* Stock icon, if any */
195 N_("_View log..."), /* Display label */
196 NULL, /* short-cut */
197 NULL, /* Tooltip */
198 G_CALLBACK (on_menu_git_log) /* action callback */
201 "ActionGitAdd", /* Action name */
202 GTK_STOCK_ADD, /* Stock icon, if any */
203 N_("_Add..."), /* Display label */
204 NULL, /* short-cut */
205 NULL, /* Tooltip */
206 G_CALLBACK (on_menu_git_add) /* action callback */
209 "ActionGitRemove", /* Action name */
210 GTK_STOCK_REMOVE, /* Stock icon, if any */
211 N_("_Remove..."), /* Display label */
212 NULL, /* short-cut */
213 NULL, /* Tooltip */
214 G_CALLBACK (on_menu_git_remove) /* action callback */
217 "ActionGitCreateBranch", /* Action name */
218 NULL, /* Stock icon, if any */
219 N_("_Create branch..."), /* Display label */
220 NULL, /* short-cut */
221 NULL, /* Tooltip */
222 G_CALLBACK (on_menu_git_create_branch) /* action callback */
225 "ActionGitDeleteBranch", /* Action name */
226 GTK_STOCK_DELETE, /* Stock icon, if any */
227 N_("_Delete branch..."), /* Display label */
228 NULL, /* short-cut */
229 NULL, /* Tooltip */
230 G_CALLBACK (on_menu_git_delete_branch) /* action callback */
233 "ActionGitSwitch", /* Action name */
234 GTK_STOCK_JUMP_TO, /* Stock icon, if any */
235 N_("_Switch to another branch..."), /* Display label */
236 NULL, /* short-cut */
237 NULL, /* Tooltip */
238 G_CALLBACK (on_menu_git_switch) /* action callback */
241 "ActionGitMerge", /* Action name */
242 GTK_STOCK_CONVERT, /* Stock icon, if any */
243 N_("_Merge..."), /* Display label */
244 NULL, /* short-cut */
245 NULL, /* Tooltip */
246 G_CALLBACK (on_menu_git_merge) /* action callback */
249 "ActionGitCreateTag", /* Action name */
250 NULL, /* Stock icon, if any */
251 N_("_Create tag..."), /* Display label */
252 NULL, /* short-cut */
253 NULL, /* Tooltip */
254 G_CALLBACK (on_menu_git_create_tag) /* action callback */
257 "ActionGitDiffUncommitted", /* Action name */
258 GTK_STOCK_ZOOM_100, /* Stock icon, if any */
259 N_("_Diff uncommitted changes"), /* Display label */
260 NULL, /* short-cut */
261 NULL, /* Tooltip */
262 G_CALLBACK (on_menu_git_diff) /* action callback */
266 static GtkActionEntry actions_log[] =
269 "ActionGitLogCommitDiff", /* Action name */
270 GTK_STOCK_ZOOM_100, /* Stock icon, if any */
271 N_("_Show commit diff"), /* Display label */
272 NULL, /* short-cut */
273 NULL, /* Tooltip */
274 G_CALLBACK (on_log_menu_git_commit_diff) /* action callback */
277 "ActionGitLogCreateBranch", /* Action name */
278 NULL, /* Stock icon, if any */
279 N_("_Create branch..."), /* Display label */
280 NULL, /* short-cut */
281 NULL, /* Tooltip */
282 G_CALLBACK (on_log_menu_git_create_branch) /* action callback */
285 "ActionGitLogCreateTag", /* Action name */
286 NULL, /* Stock icon, if any */
287 N_("_Create tag..."), /* Display label */
288 NULL, /* short-cut */
289 NULL, /* Tooltip */
290 G_CALLBACK (on_log_menu_git_create_tag) /* action callback */
293 "ActionGitLogReset", /* Action name */
294 GTK_STOCK_REFRESH, /* Stock icon, if any */
295 N_("_Reset tree..."), /* Display label */
296 NULL, /* short-cut */
297 NULL, /* Tooltip */
298 G_CALLBACK (on_log_menu_git_reset) /* action callback */
301 "ActionGitLogRevert", /* Action name */
302 GTK_STOCK_UNDO, /* Stock icon, if any */
303 N_("_Revert commit..."), /* Display label */
304 NULL, /* short-cut */
305 NULL, /* Tooltip */
306 G_CALLBACK (on_log_menu_git_revert) /* action callback */
309 "ActionMenuGitLogBisect", /* Action name */
310 NULL, /* Stock icon, if any */
311 N_("_Bisect"), /* Display label */
312 NULL, /* short-cut */
313 NULL, /* Tooltip */
314 NULL /* action callback */
317 "ActionGitLogBisectGood", /* Action name */
318 GTK_STOCK_YES, /* Stock icon, if any */
319 N_("_Set good revision"), /* Display label */
320 NULL, /* short-cut */
321 NULL, /* Tooltip */
322 G_CALLBACK (on_log_menu_git_bisect_good) /* action callback */
325 "ActionGitLogBisectBad", /* Action name */
326 GTK_STOCK_NO, /* Stock icon, if any */
327 N_("_Set bad revision"), /* Display label */
328 NULL, /* short-cut */
329 NULL, /* Tooltip */
330 G_CALLBACK (on_log_menu_git_bisect_bad) /* action callback */
334 static void
335 on_project_root_added (AnjutaPlugin *plugin, const gchar *name,
336 const GValue *value, gpointer user_data)
338 Git *git_plugin;
339 gchar *project_root_uri;
340 GFile *file;
341 AnjutaUI *ui;
342 GtkAction *git_menu_action;
344 git_plugin = ANJUTA_PLUGIN_GIT (plugin);
346 g_free (git_plugin->project_root_directory);
347 project_root_uri = g_value_dup_string (value);
348 file = g_file_new_for_uri (project_root_uri);
349 git_plugin->project_root_directory = g_file_get_path (file);
350 g_object_unref (file);
352 ui = anjuta_shell_get_ui (plugin->shell, NULL);
353 git_menu_action = anjuta_ui_get_action (ui,
354 "ActionGroupGit",
355 "ActionMenuGit");
357 gtk_action_set_sensitive (git_menu_action, TRUE);
358 gtk_widget_set_sensitive (git_plugin->log_viewer, TRUE);
360 g_free (project_root_uri);
362 git_plugin->bisect_file_monitor = bisect_menus_init (git_plugin);
365 static void
366 on_project_root_removed (AnjutaPlugin *plugin, const gchar *name,
367 gpointer user_data)
369 GtkAction *git_menu_action;
370 Git *git_plugin;
372 git_plugin = ANJUTA_PLUGIN_GIT (plugin);
374 g_free (git_plugin->project_root_directory);
375 git_plugin->project_root_directory = NULL;
377 git_menu_action = anjuta_ui_get_action (anjuta_shell_get_ui (plugin->shell,
378 NULL),
379 "ActionGroupGit",
380 "ActionMenuGit");
382 gtk_action_set_sensitive (git_menu_action, FALSE);
383 gtk_widget_set_sensitive (git_plugin->log_viewer, FALSE);
384 git_log_window_clear (git_plugin);
386 g_file_monitor_cancel (git_plugin->bisect_file_monitor);
387 g_object_unref (git_plugin->bisect_file_monitor);
390 static void
391 on_editor_added (AnjutaPlugin *plugin, const gchar *name, const GValue *value,
392 gpointer user_data)
394 Git *git_plugin;
395 gchar *current_editor_uri;
396 IAnjutaEditor *editor;
397 GFile *file;
399 git_plugin = ANJUTA_PLUGIN_GIT (plugin);
400 editor = g_value_get_object (value);
402 git_plugin->current_editor_filename = NULL;
404 if (IANJUTA_IS_EDITOR (editor))
406 g_free (git_plugin->current_editor_filename);
407 current_editor_uri = ianjuta_file_get_uri (IANJUTA_FILE (editor), NULL);
409 if (current_editor_uri)
411 file = g_file_new_for_uri (current_editor_uri);
412 g_free (current_editor_uri);
413 git_plugin->current_editor_filename = g_file_get_path (file);
414 g_object_unref (file);
419 static void
420 on_editor_removed (AnjutaPlugin *plugin, const gchar *name, gpointer user_data)
422 Git *git_plugin;
424 git_plugin = ANJUTA_PLUGIN_GIT (plugin);
426 g_free (git_plugin->current_editor_filename);
427 git_plugin->current_editor_filename = NULL;
430 static gboolean
431 git_activate_plugin (AnjutaPlugin *plugin)
433 AnjutaUI *ui;
434 Git *git_plugin;
435 GtkAction *git_menu_action;
437 DEBUG_PRINT ("Git: Activating Git plugin ...");
439 git_plugin = ANJUTA_PLUGIN_GIT (plugin);
440 ui = anjuta_shell_get_ui (plugin->shell, NULL);
442 /* Add all our actions */
443 anjuta_ui_add_action_group_entries (ui, "ActionGroupGit",
444 _("Git operations"),
445 actions_git,
446 G_N_ELEMENTS (actions_git),
447 GETTEXT_PACKAGE, TRUE, plugin);
448 anjuta_ui_add_action_group_entries (ui, "ActionGroupGitLog",
449 _("Git log operations"),
450 actions_log,
451 G_N_ELEMENTS (actions_log),
452 GETTEXT_PACKAGE, TRUE, plugin);
454 git_plugin->uiid = anjuta_ui_merge (ui, UI_FILE);
456 git_plugin->log_popup_menu = gtk_ui_manager_get_widget (GTK_UI_MANAGER (ui),
457 "/PopupLog");
459 /* Add watches */
460 git_plugin->project_root_watch_id = anjuta_plugin_add_watch (plugin,
461 "project_root_uri",
462 on_project_root_added,
463 on_project_root_removed,
464 NULL);
466 git_plugin->editor_watch_id = anjuta_plugin_add_watch (plugin,
467 "document_manager_current_editor",
468 on_editor_added,
469 on_editor_removed,
470 NULL);
472 /* Log viewer */
473 git_plugin->log_viewer = git_log_window_create (git_plugin);
474 anjuta_shell_add_widget (plugin->shell,
475 git_plugin->log_viewer,
476 "GitLogViewer",
477 _("Git Log"),
478 GTK_STOCK_ZOOM_100,
479 ANJUTA_SHELL_PLACEMENT_CENTER,
480 NULL);
481 g_object_unref (git_plugin->log_viewer);
485 /* Git needs a working directory to work with; it can't take full paths,
486 * so make sure that Git can't be used if there's no project opened. */
487 git_menu_action = anjuta_ui_get_action (anjuta_shell_get_ui (plugin->shell,
488 NULL),
489 "ActionGroupGit",
490 "ActionMenuGit");
492 if (!git_plugin->project_root_directory)
494 gtk_action_set_sensitive (git_menu_action, FALSE);
495 gtk_widget_set_sensitive (git_plugin->log_viewer, FALSE);
498 return TRUE;
501 static gboolean
502 git_deactivate_plugin (AnjutaPlugin *plugin)
504 AnjutaUI *ui = anjuta_shell_get_ui (plugin->shell, NULL);
505 Git *git_plugin;
507 git_plugin = ANJUTA_PLUGIN_GIT (plugin);
509 DEBUG_PRINT ("Git: Dectivating Git plugin ...");
510 anjuta_ui_unmerge (ui, git_plugin->uiid);
511 anjuta_plugin_remove_watch (plugin, git_plugin->project_root_watch_id,
512 TRUE);
513 anjuta_plugin_remove_watch (plugin, git_plugin->editor_watch_id,
514 TRUE);
516 anjuta_shell_remove_widget (plugin->shell, git_plugin->log_viewer, NULL);
517 gtk_widget_destroy (git_plugin->log_popup_menu);
519 return TRUE;
522 static void
523 git_finalize (GObject *obj)
525 /* Finalization codes here */
526 G_OBJECT_CLASS (parent_class)->finalize (obj);
529 static void
530 git_dispose (GObject *obj)
532 /* Disposition codes */
533 G_OBJECT_CLASS (parent_class)->dispose (obj);
536 static void
537 git_instance_init (GObject *obj)
539 Git *plugin = ANJUTA_PLUGIN_GIT (obj);
540 plugin->uiid = 0;
543 static void
544 git_class_init (GObjectClass *klass)
546 AnjutaPluginClass *plugin_class = ANJUTA_PLUGIN_CLASS (klass);
548 parent_class = g_type_class_peek_parent (klass);
550 plugin_class->activate = git_activate_plugin;
551 plugin_class->deactivate = git_deactivate_plugin;
552 klass->finalize = git_finalize;
553 klass->dispose = git_dispose;
556 ANJUTA_PLUGIN_BOILERPLATE (Git, git);
557 ANJUTA_SIMPLE_PLUGIN (Git, git);