Merge branch 'inc-sven'
[giggle.git] / src / giggle-window.c
blob07be9dbdae06a0b83c3e2b0611e85e17fa9b14db
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * Copyright (C) 2007 Imendio AB
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
21 #include <config.h>
22 #include <glib/gi18n.h>
23 #include <gtk/gtk.h>
24 #include <glade/glade.h>
25 #include <gtksourceview/gtksourceview.h>
26 #include <gtksourceview/gtksourcelanguagesmanager.h>
27 #include <string.h>
29 #include "giggle-window.h"
30 #include "giggle-error.h"
31 #include "giggle-git.h"
32 #include "giggle-git-branches.h"
33 #include "giggle-git-diff.h"
34 #include "giggle-git-revisions.h"
35 #include "giggle-revision.h"
36 #include "giggle-graph-renderer.h"
37 #include "giggle-personal-details-window.h"
39 typedef struct GiggleWindowPriv GiggleWindowPriv;
41 struct GiggleWindowPriv {
42 GtkWidget *content_vbox;
43 GtkWidget *menubar_hbox;
44 GtkWidget *revision_treeview;
45 GtkWidget *log_textview;
46 GtkWidget *diff_textview;
48 GtkCellRenderer *graph_renderer;
50 GtkUIManager *ui_manager;
52 GtkRecentManager *recent_manager;
53 GtkActionGroup *recent_action_group;
55 GiggleGit *git;
57 /* Current job in progress. */
58 GiggleJob *current_job;
61 enum {
62 REVISION_COL_OBJECT,
63 REVISION_NUM_COLS
66 static void window_finalize (GObject *object);
67 static void window_setup_revision_treeview (GiggleWindow *window);
68 static void window_setup_diff_textview (GiggleWindow *window,
69 GtkWidget *scrolled);
70 static void window_update_revision_info (GiggleWindow *window,
71 GiggleRevision *current_revision,
72 GiggleRevision *previous_revision);
73 static void window_add_widget_cb (GtkUIManager *merge,
74 GtkWidget *widget,
75 GiggleWindow *window);
76 static void window_revision_selection_changed_cb (GtkTreeSelection *selection,
77 GiggleWindow *window);
78 static void window_git_diff_result_callback (GiggleGit *git,
79 GiggleJob *job,
80 GError *error,
81 gpointer user_data);
82 static void window_revision_cell_data_log_func (GtkTreeViewColumn *tree_column,
83 GtkCellRenderer *cell,
84 GtkTreeModel *tree_model,
85 GtkTreeIter *iter,
86 gpointer data);
87 static void window_revision_cell_data_author_func (GtkTreeViewColumn *tree_column,
88 GtkCellRenderer *cell,
89 GtkTreeModel *tree_model,
90 GtkTreeIter *iter,
91 gpointer data);
92 static void window_revision_cell_data_date_func (GtkTreeViewColumn *tree_column,
93 GtkCellRenderer *cell,
94 GtkTreeModel *tree_model,
95 GtkTreeIter *iter,
96 gpointer data);
97 static void window_action_quit_cb (GtkAction *action,
98 GiggleWindow *window);
99 static void window_action_open_cb (GtkAction *action,
100 GiggleWindow *window);
101 static void window_action_save_patch_cb (GtkAction *action,
102 GiggleWindow *window);
103 static void window_action_personal_details_cb (GtkAction *action,
104 GiggleWindow *window);
105 static void window_action_about_cb (GtkAction *action,
106 GiggleWindow *window);
107 static void window_directory_changed_cb (GiggleGit *git,
108 GParamSpec *arg,
109 GiggleWindow *window);
110 static void window_git_dir_changed_cb (GiggleGit *git,
111 GParamSpec *arg,
112 GiggleWindow *window);
113 static void window_recent_repositories_update (GiggleWindow *window);
115 static const GtkActionEntry action_entries[] = {
116 { "FileMenu", NULL,
117 N_("_File"), NULL, NULL,
118 NULL
120 { "EditMenu", NULL,
121 N_("_Edit"), NULL, NULL,
122 NULL
124 { "HelpMenu", NULL,
125 N_("_Help"), NULL, NULL,
126 NULL
128 { "Open", GTK_STOCK_OPEN,
129 N_("_Open"), "<control>O", N_("Open a GIT repository"),
130 G_CALLBACK (window_action_open_cb)
132 { "SavePatch", GTK_STOCK_SAVE,
133 N_("_Save patch"), "<control>S", N_("Save a patch"),
134 G_CALLBACK (window_action_save_patch_cb)
136 { "Quit", GTK_STOCK_QUIT,
137 N_("_Quit"), "<control>Q", N_("Quit the application"),
138 G_CALLBACK (window_action_quit_cb)
140 { "PersonalDetails", NULL,
141 N_("Personal _Details"), NULL, N_("Personal details"),
142 G_CALLBACK (window_action_personal_details_cb)
144 { "About", GTK_STOCK_ABOUT,
145 N_("_About"), NULL, N_("About this application"),
146 G_CALLBACK (window_action_about_cb)
150 static const gchar *ui_layout =
151 "<ui>"
152 " <menubar name='MainMenubar'>"
153 " <menu action='FileMenu'>"
154 " <menuitem action='Open'/>"
155 " <menuitem action='SavePatch'/>"
156 " <separator/>"
157 " <placeholder name='RecentRepositories'/>"
158 " <separator/>"
159 " <menuitem action='Quit'/>"
160 " </menu>"
161 " <menu action='EditMenu'>"
162 " <menuitem action='PersonalDetails'/>"
163 " </menu>"
164 " <menu action='HelpMenu'>"
165 " <menuitem action='About'/>"
166 " </menu>"
167 " </menubar>"
168 "</ui>";
171 G_DEFINE_TYPE (GiggleWindow, giggle_window, GTK_TYPE_WINDOW)
173 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GIGGLE_TYPE_WINDOW, GiggleWindowPriv))
175 #define RECENT_FILES_GROUP "giggle"
176 #define SAVE_PATCH_UI_PATH "/ui/MainMenubar/FileMenu/SavePatch"
177 #define RECENT_REPOS_PLACEHOLDER_PATH "/ui/MainMenubar/FileMenu/RecentRepositories"
179 static void
180 giggle_window_class_init (GiggleWindowClass *class)
182 GObjectClass *object_class = G_OBJECT_CLASS (class);
184 object_class->finalize = window_finalize;
186 g_type_class_add_private (object_class, sizeof (GiggleWindowPriv));
189 static void
190 window_create_menu (GiggleWindow *window)
192 GiggleWindowPriv *priv;
193 GtkActionGroup *action_group;
194 GtkAction *action;
195 GError *error = NULL;
197 priv = GET_PRIV (window);
198 priv->ui_manager = gtk_ui_manager_new ();
199 g_signal_connect (priv->ui_manager,
200 "add_widget",
201 G_CALLBACK (window_add_widget_cb),
202 window);
204 action_group = gtk_action_group_new ("MainActions");
205 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
206 gtk_action_group_add_actions (action_group,
207 action_entries,
208 G_N_ELEMENTS (action_entries),
209 window);
210 gtk_ui_manager_insert_action_group (priv->ui_manager, action_group, 0);
212 gtk_window_add_accel_group (GTK_WINDOW (window),
213 gtk_ui_manager_get_accel_group (priv->ui_manager));
215 g_object_unref (action_group);
217 gtk_ui_manager_add_ui_from_string (priv->ui_manager, ui_layout, -1, &error);
218 if (error) {
219 g_error ("Couldn't create UI: %s}\n", error->message);
222 gtk_ui_manager_ensure_update (priv->ui_manager);
224 action = gtk_ui_manager_get_action (priv->ui_manager, SAVE_PATCH_UI_PATH);
225 gtk_action_set_sensitive (action, FALSE);
227 /* create recent repositories resources */
228 priv->recent_action_group = gtk_action_group_new ("RecentRepositories");
229 gtk_ui_manager_insert_action_group (priv->ui_manager, priv->recent_action_group, 0);
231 priv->recent_manager = gtk_recent_manager_get_default ();
232 g_signal_connect_swapped (priv->recent_manager, "changed",
233 G_CALLBACK (window_recent_repositories_update), window);
235 window_recent_repositories_update (window);
238 static void
239 giggle_window_init (GiggleWindow *window)
241 GiggleWindowPriv *priv;
242 gchar *dir;
243 GladeXML *xml;
244 GError *error = NULL;
246 priv = GET_PRIV (window);
248 priv->git = giggle_git_get ();
249 g_signal_connect (priv->git,
250 "notify::directory",
251 G_CALLBACK (window_directory_changed_cb),
252 window);
253 g_signal_connect (priv->git,
254 "notify::git-dir",
255 G_CALLBACK (window_git_dir_changed_cb),
256 window);
258 xml = glade_xml_new (GLADEDIR "/main-window.glade",
259 "content_vbox", NULL);
260 if (!xml) {
261 g_error ("Couldn't find glade file, did you install?");
264 priv->content_vbox = glade_xml_get_widget (xml, "content_vbox");
265 gtk_container_add (GTK_CONTAINER (window), priv->content_vbox);
267 priv->menubar_hbox = glade_xml_get_widget (xml, "menubar_hbox");
268 priv->revision_treeview = glade_xml_get_widget (xml, "revision_treeview");
269 window_setup_revision_treeview (window);
271 priv->log_textview = glade_xml_get_widget (xml, "log_textview");
273 window_setup_diff_textview (
274 window,
275 glade_xml_get_widget (xml, "diff_scrolledwindow"));
277 g_object_unref (xml);
279 window_create_menu (window);
281 dir = g_get_current_dir ();
283 if (!giggle_git_set_directory (priv->git, dir, &error)) {
284 GtkWidget *dialog;
286 dialog = gtk_message_dialog_new (GTK_WINDOW (window),
287 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
288 GTK_MESSAGE_ERROR,
289 GTK_BUTTONS_OK,
290 _("The directory '%s' does not look like a "
291 "GIT repository."), dir);
293 gtk_dialog_run (GTK_DIALOG (dialog));
295 gtk_widget_destroy (dialog);
298 g_free (dir);
301 static void
302 window_finalize (GObject *object)
304 GiggleWindowPriv *priv;
306 priv = GET_PRIV (object);
308 g_object_unref (priv->ui_manager);
310 if (priv->current_job) {
311 giggle_git_cancel_job (priv->git, priv->current_job);
312 g_object_unref (priv->current_job);
315 g_object_unref (priv->git);
316 g_object_unref (priv->recent_manager);
317 g_object_unref (priv->recent_action_group);
319 G_OBJECT_CLASS (giggle_window_parent_class)->finalize (object);
322 static void
323 window_recent_repositories_add (GiggleWindow *window,
324 const gchar *repository)
326 static gchar *groups[] = { RECENT_FILES_GROUP, NULL };
327 GiggleWindowPriv *priv;
328 GtkRecentData *data;
329 gchar* display_name;
331 g_return_if_fail (repository != NULL);
333 priv = GET_PRIV (window);
335 if(g_str_has_suffix(repository, "/.git")) {
336 /* "file:///path/to/project/.git" */
337 gchar* dirname = g_path_get_dirname(repository);
338 display_name = g_path_get_basename(dirname);
339 g_free(dirname);
340 } else {
341 /* "file:///path/to/project.git" */
342 gchar const *separator;
343 separator = g_strrstr(repository, G_DIR_SEPARATOR_S);
344 g_return_if_fail(separator && *separator);
345 display_name = g_strdup(separator+1);
347 data = g_slice_new0 (GtkRecentData);
348 data->display_name = display_name;
349 data->groups = groups;
350 data->mime_type = g_strdup ("x-directory/normal");
351 data->app_name = (gchar *) g_get_application_name ();
352 data->app_exec = g_strjoin (g_get_prgname (), " %u", NULL);
354 gtk_recent_manager_add_full (priv->recent_manager,
355 repository, data);
358 static void
359 window_recent_repository_activate (GtkAction *action,
360 GiggleWindow *window)
362 GiggleWindowPriv *priv;
363 const gchar *directory;
365 priv = GET_PRIV (window);
367 directory = g_object_get_data (G_OBJECT (action), "recent-action-path");
368 giggle_git_set_directory (priv->git, directory, NULL);
371 static void
372 window_recent_repositories_clear (GiggleWindow *window)
374 GiggleWindowPriv *priv;
375 GList *actions, *l;
377 priv = GET_PRIV (window);
378 actions = l = gtk_action_group_list_actions (priv->recent_action_group);
380 for (l = actions; l != NULL; l = l->next) {
381 gtk_action_group_remove_action (priv->recent_action_group, l->data);
384 g_list_free (actions);
387 /* this should not be necessary when there's
388 * GtkRecentManager/GtkUIManager integration
390 static void
391 window_recent_repositories_reload (GiggleWindow *window)
393 GiggleWindowPriv *priv;
394 GList *recent_items, *l;
395 GtkRecentInfo *info;
396 GtkAction *action;
397 guint recent_menu_id;
398 gchar *action_name, *label;
399 gint count = 0;
401 priv = GET_PRIV (window);
403 recent_items = l = gtk_recent_manager_get_items (priv->recent_manager);
404 recent_menu_id = gtk_ui_manager_new_merge_id (priv->ui_manager);
406 /* FIXME: the max count is hardcoded */
407 while (l && count < 10) {
408 info = l->data;
410 if (gtk_recent_info_has_group (info, RECENT_FILES_GROUP)) {
411 action_name = g_strdup_printf ("recent-repository-%d", count);
412 label = g_strdup (gtk_recent_info_get_uri_display (info));
414 /* FIXME: add accel? */
416 action = gtk_action_new (action_name,
417 label,
418 NULL,
419 NULL);
421 g_object_set_data_full (G_OBJECT (action), "recent-action-path",
422 g_strdup (gtk_recent_info_get_uri_display (info)),
423 (GDestroyNotify) g_free);
425 g_signal_connect (action,
426 "activate",
427 G_CALLBACK (window_recent_repository_activate),
428 window);
430 gtk_action_group_add_action (priv->recent_action_group, action);
432 gtk_ui_manager_add_ui (priv->ui_manager,
433 recent_menu_id,
434 RECENT_REPOS_PLACEHOLDER_PATH,
435 action_name,
436 action_name,
437 GTK_UI_MANAGER_MENUITEM,
438 FALSE);
440 g_object_unref (action);
441 g_free (action_name);
442 g_free (label);
443 count++;
446 l = l->next;
449 g_list_foreach (recent_items, (GFunc) gtk_recent_info_unref, NULL);
450 g_list_free (recent_items);
453 static void
454 window_recent_repositories_update (GiggleWindow *window)
456 window_recent_repositories_clear (window);
457 window_recent_repositories_reload (window);
460 static void
461 window_git_get_revisions_cb (GiggleGit *git,
462 GiggleJob *job,
463 GError *error,
464 gpointer user_data)
466 GiggleWindow *window;
467 GiggleWindowPriv *priv;
468 GtkListStore *store;
469 GtkTreeIter iter;
470 GList *revisions;
472 window = GIGGLE_WINDOW (user_data);
473 priv = GET_PRIV (window);
474 store = gtk_list_store_new (REVISION_NUM_COLS, GIGGLE_TYPE_REVISION);
475 revisions = giggle_git_revisions_get_revisions (GIGGLE_GIT_REVISIONS (job));
477 while (revisions) {
478 gtk_list_store_append (store, &iter);
479 gtk_list_store_set (store, &iter,
480 REVISION_COL_OBJECT, g_object_ref ((GObject*) revisions->data),
481 -1);
482 revisions = revisions->next;
485 giggle_graph_renderer_validate_model (GIGGLE_GRAPH_RENDERER (priv->graph_renderer), GTK_TREE_MODEL (store), 0);
486 gtk_tree_view_set_model (GTK_TREE_VIEW (priv->revision_treeview), GTK_TREE_MODEL (store));
487 g_object_unref (store);
488 g_object_unref (job);
491 static void
492 window_git_get_branches_cb (GiggleGit *git,
493 GiggleJob *job,
494 GError *error,
495 gpointer user_data)
497 /* FIXME: do something with branches */
498 g_object_unref (job);
501 static void
502 window_setup_revision_treeview (GiggleWindow *window)
504 GiggleWindowPriv *priv;
505 GtkCellRenderer *cell;
506 GtkTreeSelection *selection;
507 gint n_columns;
509 priv = GET_PRIV (window);
511 priv->graph_renderer = giggle_graph_renderer_new ();
512 gtk_tree_view_insert_column_with_attributes (
513 GTK_TREE_VIEW (priv->revision_treeview),
515 _("Graph"),
516 priv->graph_renderer,
517 "revision", REVISION_COL_OBJECT,
518 NULL);
520 cell = gtk_cell_renderer_text_new ();
521 g_object_set(cell,
522 "ellipsize", PANGO_ELLIPSIZE_END,
523 NULL);
524 n_columns = gtk_tree_view_insert_column_with_data_func (
525 GTK_TREE_VIEW (priv->revision_treeview),
527 _("Short Log"),
528 cell,
529 window_revision_cell_data_log_func,
530 window,
531 NULL);
532 gtk_tree_view_column_set_expand (
533 gtk_tree_view_get_column (GTK_TREE_VIEW (priv->revision_treeview), n_columns - 1),
534 TRUE);
536 cell = gtk_cell_renderer_text_new ();
537 gtk_tree_view_insert_column_with_data_func (
538 GTK_TREE_VIEW (priv->revision_treeview),
540 _("Author"),
541 cell,
542 window_revision_cell_data_author_func,
543 window,
544 NULL);
546 cell = gtk_cell_renderer_text_new ();
547 gtk_tree_view_insert_column_with_data_func (
548 GTK_TREE_VIEW (priv->revision_treeview),
550 _("Date"),
551 cell,
552 window_revision_cell_data_date_func,
553 window,
554 NULL);
556 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->revision_treeview));
557 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
558 gtk_tree_view_set_rubber_banding (GTK_TREE_VIEW (priv->revision_treeview), TRUE);
560 g_signal_connect (selection,
561 "changed",
562 G_CALLBACK (window_revision_selection_changed_cb),
563 window);
566 static void
567 window_setup_diff_textview (GiggleWindow *window,
568 GtkWidget *scrolled)
570 GiggleWindowPriv *priv;
571 PangoFontDescription *font_desc;
572 GtkTextBuffer *buffer;
573 GtkSourceLanguage *language;
574 GtkSourceLanguagesManager *manager;
576 priv = GET_PRIV (window);
578 priv->diff_textview = gtk_source_view_new ();
579 gtk_text_view_set_editable (GTK_TEXT_VIEW (priv->diff_textview), FALSE);
581 font_desc = pango_font_description_from_string ("monospace");
582 gtk_widget_modify_font (priv->diff_textview, font_desc);
583 pango_font_description_free (font_desc);
585 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->diff_textview));
587 manager = gtk_source_languages_manager_new ();
588 language = gtk_source_languages_manager_get_language_from_mime_type (
589 manager, "text/x-patch");
591 gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (buffer), language);
592 gtk_source_buffer_set_highlight (GTK_SOURCE_BUFFER (buffer), TRUE);
594 g_object_unref (manager);
596 gtk_widget_show (priv->diff_textview);
598 gtk_container_add (GTK_CONTAINER (scrolled), priv->diff_textview);
601 /* Update revision info. If previous_revision is not NULL, a diff between it and
602 * the current revision will be shown.
604 static void
605 window_update_revision_info (GiggleWindow *window,
606 GiggleRevision *current_revision,
607 GiggleRevision *previous_revision)
609 GiggleWindowPriv *priv;
610 const gchar *sha;
611 const gchar *log;
612 gchar *str;
613 GtkAction *action;
615 priv = GET_PRIV (window);
617 if (current_revision) {
618 sha = giggle_revision_get_sha (current_revision);
619 log = giggle_revision_get_long_log (current_revision);
620 if (!log) {
621 log = giggle_revision_get_short_log (current_revision);
623 if (!log) {
624 log = "";
626 } else {
627 sha = "";
628 log = "";
631 str = g_strdup_printf ("%s\n%s", sha, log);
633 gtk_text_buffer_set_text (
634 gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->log_textview)),
635 str, -1);
637 g_free (str);
639 /* Clear the diff view until we get new content. */
640 gtk_text_buffer_set_text (
641 gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->diff_textview)),
642 "", 0);
644 if (priv->current_job) {
645 giggle_git_cancel_job (priv->git, priv->current_job);
646 g_object_unref (priv->current_job);
647 priv->current_job = NULL;
650 if (current_revision && previous_revision) {
651 action = gtk_ui_manager_get_action (priv->ui_manager, SAVE_PATCH_UI_PATH);
652 gtk_action_set_sensitive (action, FALSE);
654 priv->current_job = giggle_git_diff_new (previous_revision, current_revision);
655 giggle_git_run_job (priv->git,
656 priv->current_job,
657 window_git_diff_result_callback,
658 window);
662 static void
663 window_add_widget_cb (GtkUIManager *merge,
664 GtkWidget *widget,
665 GiggleWindow *window)
667 GiggleWindowPriv *priv;
669 priv = GET_PRIV (window);
671 gtk_box_pack_start (GTK_BOX (priv->menubar_hbox), widget, TRUE, TRUE, 0);
674 static void
675 window_revision_selection_changed_cb (GtkTreeSelection *selection,
676 GiggleWindow *window)
678 GiggleWindowPriv *priv;
679 GtkTreeModel *model;
680 GtkTreeIter first_iter;
681 GtkTreeIter last_iter;
682 GiggleRevision *first_revision;
683 GiggleRevision *last_revision;
684 GList *rows;
685 GList *last_row;
686 gboolean valid;
688 priv = GET_PRIV (window);
689 rows = gtk_tree_selection_get_selected_rows (selection, &model);
690 first_revision = last_revision = NULL;
691 valid = FALSE;
693 if (!rows) {
694 return;
697 /* get the first row iter */
698 gtk_tree_model_get_iter (model, &first_iter,
699 (GtkTreePath *) rows->data);
701 if (g_list_length (rows) > 1) {
702 last_row = g_list_last (rows);
703 valid = gtk_tree_model_get_iter (model, &last_iter,
704 (GtkTreePath *) last_row->data);
705 } else {
706 valid = FALSE;
709 gtk_tree_model_get (model, &first_iter,
710 REVISION_COL_OBJECT, &first_revision,
711 -1);
712 if (valid) {
713 gtk_tree_model_get (model, &last_iter,
714 REVISION_COL_OBJECT, &last_revision,
715 -1);
716 } else {
717 /* maybe select a better parent? */
718 GList* parents = giggle_revision_get_parents (first_revision);
719 last_revision = parents ? g_object_ref(parents->data) : NULL;
722 window_update_revision_info (window,
723 first_revision,
724 last_revision);
726 g_object_unref (first_revision);
727 if (last_revision) {
728 g_object_unref (last_revision);
731 g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
732 g_list_free (rows);
735 static void
736 window_git_diff_result_callback (GiggleGit *git,
737 GiggleJob *job,
738 GError *error,
739 gpointer user_data)
741 GiggleWindow *window;
742 GiggleWindowPriv *priv;
743 GtkAction *action;
745 window = GIGGLE_WINDOW (user_data);
746 priv = GET_PRIV (window);
748 if (error) {
749 GtkWidget *dialog;
751 dialog = gtk_message_dialog_new (GTK_WINDOW (window),
752 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
753 GTK_MESSAGE_ERROR,
754 GTK_BUTTONS_OK,
755 _("An error ocurred when retrieving a diff:\n"
756 "%s"), error->message);
758 gtk_dialog_run (GTK_DIALOG (dialog));
759 gtk_widget_destroy (dialog);
760 } else {
761 gtk_text_buffer_set_text (
762 gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->diff_textview)),
763 giggle_git_diff_get_result (GIGGLE_GIT_DIFF (job)),
764 -1);
766 action = gtk_ui_manager_get_action (
767 priv->ui_manager,
768 SAVE_PATCH_UI_PATH);
769 gtk_action_set_sensitive (action, TRUE);
772 g_object_unref (priv->current_job);
773 priv->current_job = NULL;
776 static void
777 window_revision_cell_data_log_func (GtkTreeViewColumn *column,
778 GtkCellRenderer *cell,
779 GtkTreeModel *model,
780 GtkTreeIter *iter,
781 gpointer data)
783 GiggleWindowPriv *priv;
784 GiggleRevision *revision;
786 priv = GET_PRIV (data);
788 gtk_tree_model_get (model, iter,
789 REVISION_COL_OBJECT, &revision,
790 -1);
792 g_object_set (cell,
793 "text", giggle_revision_get_short_log (revision),
794 NULL);
796 g_object_unref (revision);
799 static void
800 window_revision_cell_data_author_func (GtkTreeViewColumn *column,
801 GtkCellRenderer *cell,
802 GtkTreeModel *model,
803 GtkTreeIter *iter,
804 gpointer data)
806 GiggleWindowPriv *priv;
807 GiggleRevision *revision;
809 priv = GET_PRIV (data);
811 gtk_tree_model_get (model, iter,
812 REVISION_COL_OBJECT, &revision,
813 -1);
815 g_object_set (cell,
816 "text", giggle_revision_get_author (revision),
817 NULL);
819 g_object_unref (revision);
822 static void
823 window_revision_cell_data_date_func (GtkTreeViewColumn *column,
824 GtkCellRenderer *cell,
825 GtkTreeModel *model,
826 GtkTreeIter *iter,
827 gpointer data)
829 GiggleWindowPriv *priv;
830 GiggleRevision *revision;
832 priv = GET_PRIV (data);
834 gtk_tree_model_get (model, iter,
835 REVISION_COL_OBJECT, &revision,
836 -1);
838 g_object_set (cell,
839 "text", giggle_revision_get_date (revision),
840 NULL);
842 g_object_unref (revision);
845 static void
846 window_action_quit_cb (GtkAction *action,
847 GiggleWindow *window)
849 gtk_main_quit ();
852 static void
853 window_action_open_cb (GtkAction *action,
854 GiggleWindow *window)
856 GiggleWindowPriv *priv;
857 GtkWidget *file_chooser;
858 const gchar *directory;
860 priv = GET_PRIV (window);
862 file_chooser = gtk_file_chooser_dialog_new (
863 _("Select GIT repository"),
864 GTK_WINDOW (window),
865 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
866 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
867 GTK_STOCK_OK, GTK_RESPONSE_OK,
868 NULL);
870 gtk_file_chooser_set_current_folder (
871 GTK_FILE_CHOOSER (file_chooser),
872 giggle_git_get_directory (priv->git));
874 if (gtk_dialog_run (GTK_DIALOG (file_chooser)) == GTK_RESPONSE_OK) {
875 directory = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (file_chooser));
877 /* FIXME: no error handling */
878 giggle_git_set_directory (priv->git, directory, NULL);
881 gtk_widget_destroy (file_chooser);
884 static void
885 window_action_save_patch_cb (GtkAction *action,
886 GiggleWindow *window)
888 GiggleWindowPriv *priv;
889 GtkWidget *file_chooser;
890 GtkTextBuffer *text_buffer;
891 GtkTextIter iter_start, iter_end;
892 gchar *text, *path;
893 GError *error = NULL;
895 priv = GET_PRIV (window);
897 file_chooser = gtk_file_chooser_dialog_new (
898 _("Save patch file"),
899 GTK_WINDOW (window),
900 GTK_FILE_CHOOSER_ACTION_SAVE,
901 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
902 GTK_STOCK_OK, GTK_RESPONSE_OK,
903 NULL);
905 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (file_chooser), TRUE);
907 /* FIXME: remember the last selected folder */
909 if (gtk_dialog_run (GTK_DIALOG (file_chooser)) == GTK_RESPONSE_OK) {
910 text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->diff_textview));
911 gtk_text_buffer_get_bounds (text_buffer, &iter_start, &iter_end);
913 text = gtk_text_buffer_get_text (text_buffer, &iter_start, &iter_end, TRUE);
914 path = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (file_chooser));
916 if (!g_file_set_contents (path, text, strlen (text), &error)) {
917 GtkWidget *dialog;
919 dialog = gtk_message_dialog_new (
920 GTK_WINDOW (window),
921 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
922 GTK_MESSAGE_ERROR,
923 GTK_BUTTONS_CLOSE,
924 _("There was an error saving to file: \n%s"),
925 error->message);
927 gtk_dialog_run (GTK_DIALOG (dialog));
929 gtk_widget_destroy (dialog);
930 g_error_free (error);
934 gtk_widget_destroy (file_chooser);
937 static void
938 window_action_personal_details_cb (GtkAction *action,
939 GiggleWindow *window)
941 GtkWidget *personal_details;
943 personal_details = giggle_personal_details_window_new ();
944 gtk_window_set_transient_for (GTK_WINDOW (personal_details),
945 GTK_WINDOW (window));
946 gtk_widget_show (personal_details);
948 g_signal_connect_after (G_OBJECT (personal_details), "response",
949 G_CALLBACK (gtk_widget_destroy), NULL);
953 static void
954 window_action_about_cb (GtkAction *action,
955 GiggleWindow *window)
957 gtk_show_about_dialog (GTK_WINDOW (window),
958 "name", "Giggle",
959 "copyright", "Copyright 2007 Imendio AB",
960 "translator-credits", _("translator-credits"),
961 NULL);
964 static void
965 window_directory_changed_cb (GiggleGit *git,
966 GParamSpec *arg,
967 GiggleWindow *window)
969 GiggleWindowPriv *priv;
970 GiggleJob *job;
971 gchar *title;
972 const gchar *directory;
974 priv = GET_PRIV (window);
976 directory = giggle_git_get_directory (git);
977 title = g_strdup_printf ("%s - Giggle", directory);
978 gtk_window_set_title (GTK_WINDOW (window), title);
979 g_free (title);
981 /* empty the treeview */
982 gtk_tree_view_set_model (GTK_TREE_VIEW (priv->revision_treeview), NULL);
984 job = giggle_git_revisions_new ();
985 giggle_git_run_job (priv->git, job,
986 window_git_get_revisions_cb,
987 window);
989 job = giggle_git_branches_new ();
990 giggle_git_run_job (priv->git, job,
991 window_git_get_branches_cb,
992 window);
995 static void
996 window_git_dir_changed_cb (GiggleGit *git,
997 GParamSpec *pspec,
998 GiggleWindow *window)
1000 /* add repository uri to recents */
1001 gchar *uri = g_filename_to_uri (giggle_git_get_git_dir (git), NULL, NULL);
1002 window_recent_repositories_add (window, uri);
1003 g_free (uri);
1006 GtkWidget *
1007 giggle_window_new (void)
1009 GtkWidget *window;
1011 window = g_object_new (GIGGLE_TYPE_WINDOW, NULL);
1013 return window;