# # # patch "lib/perl/Annotate.pm" # from [e661d1af425f89cdd8e133a7043ee460e7ab9518] # to [3816c2f97aa3c5ea60837550ac9385b95d087d34] # # patch "lib/perl/ComboAutoCompletion.pm" # from [7adc08011b27905160b19a5e86e22c705c6265f2] # to [cc02b44560887fa8b6f6f4bacf447234509d1707] # # patch "lib/perl/Common.pm" # from [baaf11283ab2242cb245d38a17ac512ad97144bc] # to [edccfd362dd15887a63ab5aa64d83bb8cbfb164a] # # patch "lib/perl/FindFiles.pm" # from [85ba835b5b5b1b5b5266973af5711fd6660652ee] # to [a82fa3026564cb11817f6961ff9844e75bbed87c] # # patch "lib/perl/FindText.pm" # from [50886e08b3cc95333c95b65e4c2dd9a51427b306] # to [6473576a783cdc54af4b39545bd9b201d7421cb4] # # patch "lib/perl/Globals.pm" # from [8f1012dc8189c846ffbb5688ed43aafe4eda9520] # to [ba055436236e17a794686537a9c427d14a4eafb0] # # patch "lib/perl/History.pm" # from [b5cc885dbd85311e972939ae03c7695885b02744] # to [e13d5bfe8471d4f1e8954ed395a2a73a37c7386c] # # patch "lib/perl/Preferences.pm" # from [ca998b905ed0288f6ae382d3297e89c64c38779e] # to [458718b2ddce656838152ac714c0595bc880368d] # # patch "mtn-browse" # from [51d2acb03063ce59f7c3ac22b46d0763d7e53d3b] # to [5e1390c6eeed92e87359d294984d4ef6bdb7841f] # ============================================================ --- lib/perl/Annotate.pm e661d1af425f89cdd8e133a7043ee460e7ab9518 +++ lib/perl/Annotate.pm 3816c2f97aa3c5ea60837550ac9385b95d087d34 @@ -54,6 +54,9 @@ sub annotation_textview_populate_popup_c # Private routines. sub annotation_textview_populate_popup_cb($$$); +sub annotation_textview_popup_menu_item_cb($$); +sub compare_file_with_previous($$); +sub compare_revision_with_parent($$); sub get_annotation_window(); sub mtn_annotate($$$$); # @@ -96,8 +99,10 @@ sub display_annotation($$$) local $instance->{in_cb} = 1; $instance->{mtn} = $mtn; + $instance->{file_name} = $file_name; + $instance->{revision_id} = $revision_id; $instance->{window}->set_title(__x("Annotated Listing Of {file}", - file => $file_name)); + file => $instance->{file_name})); $instance->{window}->show_all(); $wm->make_busy($instance, 1); @@ -108,7 +113,10 @@ sub display_annotation($$$) $instance->{appbar}->set_status(__("Annotating file")); $wm->update_gui(); - mtn_annotate(address@hidden, $mtn->get_db_name(), $revision_id, $file_name); + mtn_annotate(address@hidden, + $mtn->get_db_name(), + $revision_id, + $instance->{file_name}); # Find the longest line for future padding and also split each line into # their prefix and text parts. @@ -276,7 +284,11 @@ sub annotation_textview_populate_popup_c # the change log of the revision responsible for the text directly under # the mouse cursor. - $menu_item = Gtk2::MenuItem->new("Display Change _Log"); + $separator = Gtk2::SeparatorMenuItem->new(); + $separator->show(); + $menu->append($separator); + + $menu_item = Gtk2::MenuItem->new(__("Display Change _Log")); if (! defined($revision_part)) { $menu_item->set_sensitive(FALSE); @@ -285,60 +297,385 @@ sub annotation_textview_populate_popup_c { $menu_item->signal_connect ("activate", - sub { + \&annotation_textview_popup_menu_item_cb, + {instance => $instance, + cb => sub { + my($instance, $revision_id) = @_; + display_change_log($instance->{mtn}, + $revision_id, + "", + undef); + }, + progress_message => __("Displaying change log"), + revision_part => $revision_part}); + } + $menu_item->show(); + $menu->append($menu_item); - my($widget, $details) = @_; + $menu_item = Gtk2::MenuItem->new(__("Display File _History")); + if (! defined($revision_part)) + { + $menu_item->set_sensitive(FALSE); + } + else + { + $menu_item->signal_connect + ("activate", + \&annotation_textview_popup_menu_item_cb, + {instance => $instance, + cb => sub { + my($instance, $revision_id) = @_; + my $old_file_name; + $instance->{mtn}->get_corresponding_path + (\$old_file_name, + $instance->{revision_id}, + $instance->{file_name}, + $revision_id); + display_file_change_history + ($instance->{mtn}, + $revision_id, + $old_file_name); + }, + progress_message => __("Displaying file history"), + revision_part => $revision_part}); + } + $menu_item->show(); + $menu->append($menu_item); - return if ($details->{instance}->{in_cb}); - local $details->{instance}->{in_cb} = 1; + $menu_item = Gtk2::MenuItem->new(__("Display _Revision History")); + if (! defined($revision_part)) + { + $menu_item->set_sensitive(FALSE); + } + else + { + $menu_item->signal_connect + ("activate", + \&annotation_textview_popup_menu_item_cb, + {instance => $instance, + cb => sub { + my($instance, $revision_id) = @_; + display_revision_change_history + ($instance->{mtn}, + undef, + $revision_id); + }, + progress_message => __("Displaying revision history"), + revision_part => $revision_part}); + } + $menu_item->show(); + $menu->append($menu_item); - my @revision_ids; - my $wm = WindowManager->instance(); + $separator = Gtk2::SeparatorMenuItem->new(); + $separator->show(); + $menu->append($separator); - $wm->make_busy($details->{instance}, 1); - $instance->{appbar}-> - push($instance->{appbar}->get_status()->get_text()); - $instance->{appbar}->set_status(__("Finding change log")); - $wm->update_gui(); + $menu_item = + Gtk2::MenuItem->new(__("Compare File With Previous _Version")); + if (! defined($revision_part)) + { + $menu_item->set_sensitive(FALSE); + } + else + { + $menu_item->signal_connect + ("activate", + \&annotation_textview_popup_menu_item_cb, + {instance => $instance, + cb => sub { + my($instance, $revision_id) = @_; + compare_file_with_previous($instance, + $revision_id); + }, + progress_message => __("Doing file comparison"), + revision_part => $revision_part}); + } + $menu_item->show(); + $menu->append($menu_item); - $details->{instance}->{mtn}-> - select(address@hidden, "i:" . $details->{revision_part}); - if (scalar(@revision_ids) == 1) - { - display_change_log($details->{instance}->{mtn}, - $revision_ids[0], - "", - undef); - } - else - { - my $dialog = Gtk2::MessageDialog->new - ($instance->{window}, - ["modal"], - "warning", - "close", - __("Cannot access unique revision id.")); - $dialog->run(); - $dialog->destroy(); - } + $menu_item = + Gtk2::MenuItem->new(__("Compare Revision _With Parent")); + if (! defined($revision_part)) + { + $menu_item->set_sensitive(FALSE); + } + else + { + $menu_item->signal_connect + ("activate", + \&annotation_textview_popup_menu_item_cb, + {instance => $instance, + cb => sub { + my($instance, $revision_id) = @_; + compare_revision_with_parent + ($instance, $revision_id); + }, + progress_message => __("Doing revision comparison"), + revision_part => $revision_part}); + } + $menu_item->show(); + $menu->append($menu_item); - $instance->{appbar}->pop(); - $wm->make_busy($details->{instance}, 0); +} +# +############################################################################## +# +# Routine - annotation_textview_popup_menu_item_cb +# +# Description - Callback routine called when the user selects an item on +# the annotation textview's popup menu. +# +# Data - $widget : The widget object that received the signal. +# $menu : The Gtk2::Menu widget that is to be updated. +# $details : A reference to an anonymous hash containing the +# window instance, callback routine, progress +# message and the revision start string that is +# associated with this widget. +# +############################################################################## - }, - {instance => $instance, - revision_part => $revision_part}); + + +sub annotation_textview_popup_menu_item_cb($$) +{ + + my($widget, $details) = @_; + + return if ($details->{instance}->{in_cb}); + local $details->{instance}->{in_cb} = 1; + + my @revision_ids; + my $wm = WindowManager->instance(); + + $wm->make_busy($details->{instance}, 1); + $details->{instance}->{appbar}-> + push($details->{instance}->{appbar}->get_status()->get_text()); + $details->{instance}->{appbar}->set_status($details->{progress_message}); + $wm->update_gui(); + + $details->{instance}->{mtn}-> + select(address@hidden, "i:" . $details->{revision_part}); + if (scalar(@revision_ids) == 1) + { + $details->{cb}($details->{instance}, $revision_ids[0]); } - $menu_item->show(); - $separator = Gtk2::SeparatorMenuItem->new(); - $separator->show(); - $menu->append($separator); - $menu->append($menu_item); + else + { + my $dialog = Gtk2::MessageDialog->new + ($details->{instance}->{window}, + ["modal"], + "warning", + "close", + __("Cannot access unique revision id.")); + $wm->allow_input(sub { $dialog->run(); }); + $dialog->destroy(); + } + $details->{instance}->{appbar}->pop(); + $wm->make_busy($details->{instance}, 0); + } # ############################################################################## # +# Routine - compare_file_with_previous +# +# Description - Compare the annotate file at the specified version with the +# previous version of the file. +# +# Data - $instance : The window instance that is associated with +# the annotation window. +# $revision_id : The revision id on which this file changed. +# +############################################################################## + + + +sub compare_file_with_previous($$) +{ + + my($instance, $revision_id) = @_; + + my(@chg_ancestors, + $file_name, + $old_file_name, + @parents); + my $wm = WindowManager->instance(); + + # Remember that a warning is generated when one goes back beyond a file's + # addition revision, so temporarily disable the warning handler. + + { + + local $suppress_mtn_warnings = 1; + + # First get the name of the file at the specified revision (it might + # have been moved or renamed). + + $instance->{mtn}->get_corresponding_path(\$file_name, + $instance->{revision_id}, + $instance->{file_name}, + $revision_id); + + # Get the revision's parent and then find out when the file last + # changed. + + $instance->{mtn}->parents(address@hidden, $revision_id); + if (scalar(@parents) > 1) + { + my $dialog = Gtk2::MessageDialog->new + ($instance->{window}, + ["modal"], + "info", + "close", + __("The selected revision has more than one parent.\n" + . "I will display the file's history so you can select\n" + . "the specific parent revision.")); + $wm->allow_input(sub { $dialog->run(); }); + $dialog->destroy(); + display_file_change_history($instance->{mtn}, + $revision_id, + $file_name); + return; + } + elsif (scalar(@parents) == 0) + { + my $dialog = Gtk2::MessageDialog->new + ($instance->{window}, + ["modal"], + "info", + "close", + __("The selected revision has no parents.")); + $wm->allow_input(sub { $dialog->run(); }); + $dialog->destroy(); + return; + } + $instance->{mtn}->get_content_changed(address@hidden, + $parents[0], + $file_name); + if (scalar(@chg_ancestors) > 1) + { + my $dialog = Gtk2::MessageDialog->new + ($instance->{window}, + ["modal"], + "info", + "close", + __("The current version of the file probably\n" + . "resulted from a merge as it is directly\n" + . "descended from multiple versions.\n" + . "I will display the file's history so you\n" + . "can select the specific parent revision.")); + $wm->allow_input(sub { $dialog->run(); }); + $dialog->destroy(); + display_file_change_history($instance->{mtn}, + $revision_id, + $file_name); + return; + } + elsif (scalar(@chg_ancestors) == 0) + { + my $dialog = Gtk2::MessageDialog->new + ($instance->{window}, + ["modal"], + "info", + "close", + __("The selected file version has no ancestors.")); + $wm->allow_input(sub { $dialog->run(); }); + $dialog->destroy(); + return; + } + + } + + # Ok now make sure the file name hasn't changed. If it has then use the + # external differences tool. + + $instance->{mtn}->get_corresponding_path(\$old_file_name, + $revision_id, + $file_name, + $chg_ancestors[0]); + if ($old_file_name ne $file_name) + { + display_renamed_file_comparison($instance->{window}, + $instance->{mtn}, + $chg_ancestors[0], + $old_file_name, + $revision_id, + $file_name); + } + else + { + display_revision_comparison($instance->{mtn}, + $chg_ancestors[0], + $revision_id, + $file_name); + } + +} +# +############################################################################## +# +# Routine - compare_revision_with_parent +# +# Description - Compare the revision at the specified version with its +# parent. +# +# Data - $instance : The window instance that is associated with +# the annotation window. +# $revision_id : The revision id that is to be compared +# against its parent. +# +############################################################################## + + + +sub compare_revision_with_parent($$) +{ + + my($instance, $revision_id) = @_; + + my @parents; + my $wm = WindowManager->instance(); + + # First get the revision's parent(s). + + $instance->{mtn}->parents(address@hidden, $revision_id); + if (scalar(@parents) > 1) + { + my $dialog = Gtk2::MessageDialog->new + ($instance->{window}, + ["modal"], + "info", + "close", + __("The selected revision has more than one parent.\n" + . "I will display the revision's history so you can select\n" + . "the specific parent revision.")); + $wm->allow_input(sub { $dialog->run(); }); + $dialog->destroy(); + display_revision_change_history($instance->{mtn}, undef, $revision_id); + return; + } + elsif (scalar(@parents) == 0) + { + my $dialog = Gtk2::MessageDialog->new + ($instance->{window}, + ["modal"], + "info", + "close", + __("The selected revision has no parents.")); + $wm->allow_input(sub { $dialog->run(); }); + $dialog->destroy(); + return; + } + + # Ok now compare the revisions and display the results. + + display_revision_comparison($instance->{mtn}, $parents[0], $revision_id); + +} +# +############################################################################## +# # Routine - get_annotation_window # # Description - Creates or prepares an existing annotation window for use. ============================================================ --- lib/perl/ComboAutoCompletion.pm 7adc08011b27905160b19a5e86e22c705c6265f2 +++ lib/perl/ComboAutoCompletion.pm cc02b44560887fa8b6f6f4bacf447234509d1707 @@ -174,21 +174,21 @@ sub comboboxentry_key_release_event_cb($ $combo = $instance->{branch_comboboxentry}; $change_state = BRANCH_CHANGED; $combo_details = $instance->{branch_combo_details}; - $name = "branch"; + $name = __("branch"); } elsif ($widget == $instance->{revision_comboboxentry}) { $combo = $instance->{revision_comboboxentry}; $change_state = REVISION_CHANGED; $combo_details = $instance->{revision_combo_details}; - $name = "revision"; + $name = __("revision"); } elsif ($widget == $instance->{directory_comboboxentry}) { $combo = $instance->{directory_comboboxentry}; $change_state = DIRECTORY_CHANGED; $combo_details = $instance->{directory_combo_details}; - $name = "directory"; + $name = __("directory"); } else { ============================================================ --- lib/perl/Common.pm baaf11283ab2242cb245d38a17ac512ad97144bc +++ lib/perl/Common.pm edccfd362dd15887a63ab5aa64d83bb8cbfb164a @@ -611,7 +611,8 @@ sub treeview_setup_search_column_selecti # Create a popup menu with the search option in it. $menu = Gtk2::Menu->new(); - $menu_item = Gtk2::MenuItem->new("Select As Search Column"); + $menu_item = + Gtk2::MenuItem->new(__("Select As Search Column")); $menu->append($menu_item); $menu_item->show(); @@ -1155,7 +1156,8 @@ sub handle_comboxentry_history($$;$) "warning", "close", __("Your preferences could not be saved:\n") . $@); - $dialog->run(); + WindowManager->instance()->allow_input + (sub { $dialog->run(); }); $dialog->destroy(); } } ============================================================ --- lib/perl/FindFiles.pm 85ba835b5b5b1b5b5266973af5711fd6660652ee +++ lib/perl/FindFiles.pm a82fa3026564cb11817f6961ff9844e75bbed87c @@ -1045,7 +1045,8 @@ sub validate_query($$) my($instance, $query) = @_; - my($re_text); + my $re_text; + my $wm = WindowManager->instance(); # Check that the file name glob is valid. @@ -1063,7 +1064,7 @@ sub validate_query($$) "close", __x("`{pattern}' is an invalid\nfile name pattern.", pattern => $query->{file_glob})); - $dialog->run(); + $wm->allow_input(sub { $dialog->run(); }); $dialog->destroy(); return; } @@ -1086,7 +1087,7 @@ sub validate_query($$) "close", __x("`{pattern}' is an invalid\ncontent search pattern.", pattern => $query->{contents_pattern})); - $dialog->run(); + $wm->allow_input(sub { $dialog->run(); }); $dialog->destroy(); return; } @@ -1104,7 +1105,7 @@ sub validate_query($$) "close", __("The `between' dates are either\n" . "the same or the wrong way round.")); - $dialog->run(); + $wm->allow_input(sub { $dialog->run(); }); $dialog->destroy(); return; } @@ -1124,7 +1125,7 @@ sub validate_query($$) "close", __x("A duration of {months} months is too long.", months => $query->{period})); - $dialog->run(); + $wm->allow_input(sub { $dialog->run(); }); $dialog->destroy(); return; } @@ -1138,7 +1139,7 @@ sub validate_query($$) "close", __x("A duration of {years} years is too long.", years => $query->{period})); - $dialog->run(); + $wm->allow_input(sub { $dialog->run(); }); $dialog->destroy(); return; } ============================================================ --- lib/perl/FindText.pm 50886e08b3cc95333c95b65e4c2dd9a51427b306 +++ lib/perl/FindText.pm 6473576a783cdc54af4b39545bd9b201d7421cb4 @@ -169,7 +169,7 @@ sub enable_find_text($$) } } - # Ammend the textview object to reflect its file text enabled/disabled + # Amend the textview object to reflect its file text enabled/disabled # state. if ($enable) @@ -241,7 +241,7 @@ sub find_text_textview_populate_popup_cb # Add a `Find' option to the right-click menu that displays the find text # dialog. - $menu_item = Gtk2::MenuItem->new("_Find"); + $menu_item = Gtk2::MenuItem->new(__("_Find")); if ($widget->{find_text_disabled}) { $menu_item->set_sensitive(FALSE); ============================================================ --- lib/perl/Globals.pm 8f1012dc8189c846ffbb5688ed43aafe4eda9520 +++ lib/perl/Globals.pm ba055436236e17a794686537a9c427d14a4eafb0 @@ -110,6 +110,10 @@ our $mime_match_table; our $mime_match_table; +# Whether Monotone warnings should be suppressed or not. + +our $suppress_mtn_warnings; + # ***** PACKAGE INFORMATION ***** use base qw(Exporter); @@ -135,6 +139,7 @@ our %EXPORT_TAGS = (constants => [qw(ALL $line_image $mime_match_table $mono_font + $suppress_mtn_warnings $tmp_dir $tooltips $user_preferences)]); ============================================================ --- lib/perl/History.pm b5cc885dbd85311e972939ae03c7695885b02744 +++ lib/perl/History.pm e13d5bfe8471d4f1e8954ed395a2a73a37c7386c @@ -80,14 +80,15 @@ sub display_file_change_history($$$); # Public routines. sub display_file_change_history($$$); +sub display_renamed_file_comparison($$$$$$); sub display_revision_change_history($$$); +sub display_revision_comparison($$$;$); # Private routines. sub compare_button_clicked_cb($$); -sub compare_revisions($$$;$); sub comparison_revision_change_log_button_clicked_cb($$); -sub external_diffs($$$$$); +sub external_diffs($$$$$$); sub external_diffs_button_clicked_cb($$); sub file_comparison_combobox_changed_cb($$); sub get_file_history_helper($$$); @@ -356,10 +357,12 @@ sub display_file_change_history($$$) $instance->{stop_button}->set_sensitive(TRUE); $wm->update_gui(); $instance->{revision_hits} = {}; - Monotone::AutomateStdio->register_error_handler(MTN_SEVERITY_WARNING); - get_file_history_helper($instance, $revision_id, \$instance->{file_name}); - Monotone::AutomateStdio->register_error_handler(MTN_SEVERITY_ALL, - \&mtn_error_handler); + { + local $suppress_mtn_warnings = 1; + get_file_history_helper($instance, + $revision_id, + \$instance->{file_name}); + } $instance->{stop_button}->set_sensitive(FALSE); # Sort the list. @@ -500,282 +503,9 @@ sub display_file_change_history($$$) # ############################################################################## # -# Routine - history_list_button_clicked_cb +# Routine - display_revision_comparison # -# Description - Callback routine called when the user clicks on any of the -# buttons displayed in the history list in a history window. -# -# Data - $widget : The widget object that received the signal. -# $details : A reference to an anonymous hash containing the -# window instance, revision and action that is -# associated with this widget. -# -############################################################################## - - - -sub history_list_button_clicked_cb($$) -{ - - my($widget, $details) = @_; - - my($instance, - $revision_id); - - $instance = $details->{instance}; - $revision_id = $details->{revision_id}; - - return if ($instance->{in_cb}); - local $instance->{in_cb} = 1; - - if ($details->{button_type} eq "1" || $details->{button_type} eq "2") - { - if ($details->{button_type} eq "1") - { - $instance->{first_revision_id} = $revision_id; - set_label_value($instance->{revision_id_1_value_label}, - $revision_id); - if ($instance->{first_revision_id} - eq $instance->{second_revision_id}) - { - $instance->{second_revision_id} = ""; - set_label_value($instance->{revision_id_2_value_label}, ""); - } - } - else - { - $instance->{second_revision_id} = $revision_id; - set_label_value($instance->{revision_id_2_value_label}, - $revision_id); - if ($instance->{second_revision_id} - eq $instance->{first_revision_id}) - { - $instance->{first_revision_id} = ""; - set_label_value($instance->{revision_id_1_value_label}, ""); - } - } - if ($instance->{first_revision_id} ne "" - && $instance->{second_revision_id} ne "") - { - $instance->{compare_button}->set_sensitive(TRUE); - } - else - { - $instance->{compare_button}->set_sensitive(FALSE); - } - } - elsif ($details->{button_type} eq "browse-revision") - { - - my($branch, - @certs_list); - - # First find out what branch the revision is on (take the first one). - - $instance->{mtn}->certs(address@hidden, $revision_id); - $branch = ""; - foreach my $cert (@certs_list) - { - if ($cert->{name} eq "branch") - { - $branch = $cert->{value}; - last; - } - } - - # Get a new browser window preloaded with the desired file. - - get_browser_window($instance->{mtn}, $branch, $revision_id); - - } - elsif ($details->{button_type} eq "browse-file") - { - - my($branch, - @certs_list, - $dir, - $file, - $path_ref); - - # First find out what branch the revision is on (take the first one). - - $instance->{mtn}->certs(address@hidden, $revision_id); - $branch = ""; - foreach my $cert (@certs_list) - { - if ($cert->{name} eq "branch") - { - $branch = $cert->{value}; - last; - } - } - - # Split the file name into directory and file components. - - $path_ref = $instance->{revision_hits}->{$revision_id}; - $dir = dirname($$path_ref); - $dir = "" if ($dir eq "."); - $file = basename($$path_ref); - - # Get a new browser window preloaded with the desired file. - - get_browser_window($instance->{mtn}, - $branch, - $revision_id, - $dir, - $file); - - } - else - { - - # Display the full revision change log. - - display_change_log($instance->{mtn}, $revision_id); - - } - -} -# -############################################################################## -# -# Routine - compare_button_clicked_cb -# -# Description - Callback routine called when the user clicks on the -# revision comparison button in a history window. -# -# Data - $widget : The widget object that received the signal. -# $instance : The window instance that is associated with -# this widget. -# -############################################################################## - - - -sub compare_button_clicked_cb($$) -{ - - my($widget, $instance) = @_; - - return if ($instance->{in_cb}); - local $instance->{in_cb} = 1; - - my @revision_ids; - - # Sort the revisions by date, oldest first. - - @revision_ids = ($instance->{first_revision_id}, - $instance->{second_revision_id}); - $instance->{mtn}->toposort(address@hidden, @revision_ids); - - # If a file is being compared and it has been renamed between the two - # comparison revisions then we have to fall back on the external helper - # application, otherwise we can use Monotone's comparison feature. - - if (defined($instance->{file_name}) - && $instance->{revision_hits}->{$revision_ids[0]} - != $instance->{revision_hits}->{$revision_ids[1]}) - { - - my($answer, - $dialog, - @manifest, - $new_file_id, - $old_file_id); - - $dialog = Gtk2::MessageDialog->new - ($instance->{window}, - ["modal"], - "question", - "yes-no", - __("The name of the selected file has changed\n" - . "between the two selected revisions and cannot\n" - . "be compared internally. Would you like to do\n" - . "the comparison using the external helper application?")); - $dialog->set_title(__("External Comparison")); - $answer = $dialog->run(); - $dialog->destroy(); - - # Only continue if asked to do so. - - if ($answer eq "yes") - { - - # Get the manifests of the two revisions and look for the files in - # order to get their file ids. - - $instance->{mtn}->get_manifest_of(address@hidden, $revision_ids[0]); - foreach my $entry (@manifest) - { - if ($entry->{name} - eq ${$instance->{revision_hits}->{$revision_ids[0]}}) - { - $old_file_id = $entry->{file_id}; - last; - } - } - $instance->{mtn}->get_manifest_of(address@hidden, $revision_ids[1]); - foreach my $entry (@manifest) - { - if ($entry->{name} - eq ${$instance->{revision_hits}->{$revision_ids[1]}}) - { - $new_file_id = $entry->{file_id}; - last; - } - } - - # Make sure we have the file ids. - - if (! defined($old_file_id) || ! defined ($new_file_id)) - { - my $dialog; - $dialog = Gtk2::MessageDialog->new - ($instance->{window}, - ["modal"], - "warning", - "close", - __("The file contents cannot be\n" - . "found in the select revisions.\n" - . "This should not be happening.")); - $dialog->run(); - $dialog->destroy(); - return; - } - - # Use the external helper application to compare the files. - - external_diffs($instance, - ${$instance->{revision_hits}->{$revision_ids[0]}}, - $old_file_id, - ${$instance->{revision_hits}->{$revision_ids[1]}}, - $new_file_id); - - } - - } - else - { - - # Use Monotone's comparison feature. - - compare_revisions($instance->{mtn}, - $revision_ids[0], - $revision_ids[1], - defined($instance->{file_name}) - ? ${$instance->{revision_hits}-> - {$revision_ids[0]}} - : undef); - - } - -} -# -############################################################################## -# -# Routine - compare_revisions -# -# Description - Compares and then displays the differeneces between the two +# Description - Compares and then displays the differences between the two # specified revisions, optionally restricting it to the # specified file. # @@ -794,7 +524,7 @@ sub compare_button_clicked_cb($$) -sub compare_revisions($$$;$) +sub display_revision_comparison($$$;$) { my($mtn, $revision_id_1, $revision_id_2, $file_name) = @_; @@ -1216,6 +946,321 @@ sub compare_revisions($$$;$) # ############################################################################## # +# Routine - display_renamed_file_comparison +# +# Description - Compares and then displays the differences between two +# versions of a file that has either been renamed or moved +# somewhere between the specified revisions. The comparison +# has to be done with the external helper application. +# +# Data - $parent : The parent window widget for any dialogs +# that may appear. +# $mtn : The Monotone::AutomateStdio object that +# is to be used to get the files' details. +# $old_revision_id : The revision id for the older revision. +# $old_file_name : The name of the file on the older +# $new_revision_id : The revision id for the newer revision. +# $new_file_name : The name of the file on the newer +# revision. +# +############################################################################## + + + +sub display_renamed_file_comparison($$$$$$) +{ + + my($parent, + $mtn, + $old_revision_id, + $old_file_name, + $new_revision_id, + $new_file_name) = @_; + + my($answer, + $dialog, + @manifest, + $new_file_id, + $old_file_id); + my $wm = WindowManager->instance(); + + $dialog = Gtk2::MessageDialog->new + ($parent, + ["modal"], + "question", + "yes-no", + __("The name of the selected file has changed\n" + . "between the two selected revisions and cannot\n" + . "be compared internally. Would you like to do\n" + . "the comparison using the external helper application?")); + $dialog->set_title(__("External Comparison")); + $wm->allow_input(sub { $answer = $dialog->run(); }); + $dialog->destroy(); + + # Only continue if asked to do so. + + if ($answer eq "yes") + { + + # Get the manifests of the two revisions and look for the files in + # order to get their file ids. + + $mtn->get_manifest_of(address@hidden, $old_revision_id); + foreach my $entry (@manifest) + { + if ($entry->{name} eq $old_file_name) + { + $old_file_id = $entry->{file_id}; + last; + } + } + $mtn->get_manifest_of(address@hidden, $new_revision_id); + foreach my $entry (@manifest) + { + if ($entry->{name} eq $new_file_name) + { + $new_file_id = $entry->{file_id}; + last; + } + } + + # Make sure we have the file ids. + + if (! defined($old_file_id) || ! defined ($new_file_id)) + { + my $dialog; + $dialog = Gtk2::MessageDialog->new + ($parent, + ["modal"], + "warning", + "close", + __("The file contents cannot be\n" + . "found in the selected revisions.\n" + . "This should not be happening.")); + $wm->allow_input(sub { $dialog->run(); }); + $dialog->destroy(); + return; + } + + # Use the external helper application to compare the files. + + external_diffs($parent, + $mtn, + $old_file_name, + $old_file_id, + $new_file_name, + $new_file_id); + + } + +} +# +############################################################################## +# +# Routine - history_list_button_clicked_cb +# +# Description - Callback routine called when the user clicks on any of the +# buttons displayed in the history list in a history window. +# +# Data - $widget : The widget object that received the signal. +# $details : A reference to an anonymous hash containing the +# window instance, revision and action that is +# associated with this widget. +# +############################################################################## + + + +sub history_list_button_clicked_cb($$) +{ + + my($widget, $details) = @_; + + my($instance, + $revision_id); + + $instance = $details->{instance}; + $revision_id = $details->{revision_id}; + + return if ($instance->{in_cb}); + local $instance->{in_cb} = 1; + + if ($details->{button_type} eq "1" || $details->{button_type} eq "2") + { + if ($details->{button_type} eq "1") + { + $instance->{first_revision_id} = $revision_id; + set_label_value($instance->{revision_id_1_value_label}, + $revision_id); + if ($instance->{first_revision_id} + eq $instance->{second_revision_id}) + { + $instance->{second_revision_id} = ""; + set_label_value($instance->{revision_id_2_value_label}, ""); + } + } + else + { + $instance->{second_revision_id} = $revision_id; + set_label_value($instance->{revision_id_2_value_label}, + $revision_id); + if ($instance->{second_revision_id} + eq $instance->{first_revision_id}) + { + $instance->{first_revision_id} = ""; + set_label_value($instance->{revision_id_1_value_label}, ""); + } + } + if ($instance->{first_revision_id} ne "" + && $instance->{second_revision_id} ne "") + { + $instance->{compare_button}->set_sensitive(TRUE); + } + else + { + $instance->{compare_button}->set_sensitive(FALSE); + } + } + elsif ($details->{button_type} eq "browse-revision") + { + + my($branch, + @certs_list); + + # First find out what branch the revision is on (take the first one). + + $instance->{mtn}->certs(address@hidden, $revision_id); + $branch = ""; + foreach my $cert (@certs_list) + { + if ($cert->{name} eq "branch") + { + $branch = $cert->{value}; + last; + } + } + + # Get a new browser window preloaded with the desired file. + + get_browser_window($instance->{mtn}, $branch, $revision_id); + + } + elsif ($details->{button_type} eq "browse-file") + { + + my($branch, + @certs_list, + $dir, + $file, + $path_ref); + + # First find out what branch the revision is on (take the first one). + + $instance->{mtn}->certs(address@hidden, $revision_id); + $branch = ""; + foreach my $cert (@certs_list) + { + if ($cert->{name} eq "branch") + { + $branch = $cert->{value}; + last; + } + } + + # Split the file name into directory and file components. + + $path_ref = $instance->{revision_hits}->{$revision_id}; + $dir = dirname($$path_ref); + $dir = "" if ($dir eq "."); + $file = basename($$path_ref); + + # Get a new browser window preloaded with the desired file. + + get_browser_window($instance->{mtn}, + $branch, + $revision_id, + $dir, + $file); + + } + else + { + + # Display the full revision change log. + + display_change_log($instance->{mtn}, $revision_id); + + } + +} +# +############################################################################## +# +# Routine - compare_button_clicked_cb +# +# Description - Callback routine called when the user clicks on the +# revision comparison button in a history window. +# +# Data - $widget : The widget object that received the signal. +# $instance : The window instance that is associated with +# this widget. +# +############################################################################## + + + +sub compare_button_clicked_cb($$) +{ + + my($widget, $instance) = @_; + + return if ($instance->{in_cb}); + local $instance->{in_cb} = 1; + + my @revision_ids; + + # Sort the revisions by date, oldest first. + + @revision_ids = ($instance->{first_revision_id}, + $instance->{second_revision_id}); + $instance->{mtn}->toposort(address@hidden, @revision_ids); + + # If a file is being compared and it has been renamed between the two + # comparison revisions then we have to fall back on the external helper + # application, otherwise we can use Monotone's comparison feature. + + if (defined($instance->{file_name}) + && $instance->{revision_hits}->{$revision_ids[0]} + != $instance->{revision_hits}->{$revision_ids[1]}) + { + display_renamed_file_comparison($instance->{window}, + $instance->{mtn}, + $revision_ids[0], + ${$instance->{revision_hits}-> + {$revision_ids[0]}}, + $revision_ids[1], + ${$instance->{revision_hits}-> + {$revision_ids[1]}}); + } + else + { + + # Use Monotone's comparison feature. + + display_revision_comparison($instance->{mtn}, + $revision_ids[0], + $revision_ids[1], + defined($instance->{file_name}) + ? ${$instance->{revision_hits}-> + {$revision_ids[0]}} + : undef); + + } + +} +# +############################################################################## +# # Routine - file_comparison_combobox_changed_cb # # Description - Callback routine called when the user changes the value of @@ -1317,7 +1362,12 @@ sub external_diffs_button_clicked_cb($$) # Use the external helper application to compare the files. - external_diffs($instance, $file_name, $file_id_1, $file_name, $file_id_2); + external_diffs($instance->{window}, + $instance->{mtn}, + $file_name, + $file_id_1, + $file_name, + $file_id_2); } # @@ -1556,14 +1606,14 @@ sub get_file_history_helper($$$) return if ($instance->{stop}); - my(@changed_ancestors); + my @changed_ancestors; $instance->{mtn}->get_content_changed(address@hidden, $revision_id, $$file_name_ref); - foreach my $revision (@changed_ancestors) + foreach my $chg_ancestor (@changed_ancestors) { - if (! exists($instance->{revision_hits}->{$revision})) + if (! exists($instance->{revision_hits}->{$chg_ancestor})) { my @parents; @@ -1572,14 +1622,14 @@ sub get_file_history_helper($$$) # bother if the ancestor revision is the same as the current one as # we were passed the file name). - if ($revision ne $revision_id) + if ($chg_ancestor ne $revision_id) { my $file_name; $instance->{mtn}-> get_corresponding_path(\$file_name, $revision_id, $$file_name_ref, - $revision); + $chg_ancestor); $file_name_ref = \$file_name if ($file_name ne $$file_name_ref); } @@ -1588,7 +1638,7 @@ sub get_file_history_helper($$$) # hash, this can be used later to refer to the correct file name # for a given changed ancestor revision. - $instance->{revision_hits}->{$revision} = $file_name_ref; + $instance->{revision_hits}->{$chg_ancestor} = $file_name_ref; set_label_value($instance->{numbers_value_label}, scalar(keys(%{$instance->{revision_hits}}))); @@ -1596,12 +1646,12 @@ sub get_file_history_helper($$$) # Now repeat for each parent, remembering to track file renames. - $instance->{mtn}->parents(address@hidden, $revision); + $instance->{mtn}->parents(address@hidden, $chg_ancestor); foreach my $parent (@parents) { my $file_name; $instance->{mtn}->get_corresponding_path(\$file_name, - $revision, + $chg_ancestor, $$file_name_ref, $parent); $file_name_ref = \$file_name @@ -1820,7 +1870,10 @@ sub get_revision_comparison_window() # Description - Launch the external differences helper program, loading in # the contents of the specified files. # -# Data - $instance : The revision history window instance. +# Data - $parent : The parent window widget for any dialogs +# that may appear. +# $mtn : The Monotone::AutomateStdio object that is +# to be used to get the files' details. # $old_file_name : The file name of the older version of the # file. # $old_file_id : Monotone's file id for the older version @@ -1834,11 +1887,15 @@ sub get_revision_comparison_window() -sub external_diffs($$$$$) +sub external_diffs($$$$$$) { - my($instance, $old_file_name, $old_file_id, $new_file_name, $new_file_id) - = @_; + my($parent, + $mtn, + $old_file_name, + $old_file_id, + $new_file_name, + $new_file_id) = @_; my($cmd, $data, @@ -1846,7 +1903,27 @@ sub external_diffs($$$$$) $new_file, $old_fh, $old_file); + my $wm = WindowManager->instance(); + # Just check that we do actually have an external helper application to + # call. + + if (! defined($user_preferences->{diffs_application}) + || $user_preferences->{diffs_application} =~ m/^\s*$/) + { + my $dialog = Gtk2::MessageDialog->new + ($parent, + ["modal"], + "warning", + "close", + __("Cannot call the external helper application\n" + . "to do the comparison as one has not been\n" + . "specified in the user's preferences.")); + $wm->allow_input(sub { $dialog->run(); }); + $dialog->destroy(); + return; + } + # Generate temporary disk file names. if (! defined($old_file = generate_tmp_path(__("OLDER_") @@ -1856,12 +1933,12 @@ sub external_diffs($$$$$) . basename($new_file_name)))) { my $dialog = Gtk2::MessageDialog->new - ($instance->{window}, + ($parent, ["modal"], "warning", __x("Cannot generate temporary file name:\n{error_message}.", error_message => $!)); - $dialog->run(); + $wm->allow_input(sub { $dialog->run(); }); $dialog->destroy(); return; } @@ -1872,20 +1949,20 @@ sub external_diffs($$$$$) || ! defined($new_fh = IO::File->new($new_file, "w"))) { my $dialog = Gtk2::MessageDialog->new - ($instance->{window}, + ($parent, ["modal"], "warning", "close", __x("{error_message}.", error_message => $!)); - $dialog->run(); + $wm->allow_input(sub { $dialog->run(); }); $dialog->destroy(); return; } binmode($old_fh); binmode($new_fh); - $instance->{mtn}->get_file(\$data, $old_file_id); + $mtn->get_file(\$data, $old_file_id); $old_fh->print($data); - $instance->{mtn}->get_file(\$data, $new_file_id); + $mtn->get_file(\$data, $new_file_id); $new_fh->print($data); $old_fh->close(); $new_fh->close(); ============================================================ --- lib/perl/Preferences.pm ca998b905ed0288f6ae382d3297e89c64c38779e +++ lib/perl/Preferences.pm 458718b2ddce656838152ac714c0595bc880368d @@ -1510,7 +1510,7 @@ sub validate_preferences($) "close", __("The external file comparison application field is\n" . "invalid, please correct before attempting to resave.")); - $dialog->run(); + WindowManager->instance()->allow_input(sub { $dialog->run(); }); $dialog->destroy(); return; } ============================================================ --- mtn-browse 51d2acb03063ce59f7c3ac22b46d0763d7e53d3b +++ mtn-browse 5e1390c6eeed92e87359d294984d4ef6bdb7841f @@ -2607,6 +2607,8 @@ sub setup_mtn_object($$) my($mtn, $parent) = @_; + my $wm = WindowManager->instance(); + if ($user_preferences->{show_suspended}) { if ($mtn->can(MTN_IGNORE_SUSPEND_CERTS)) @@ -2623,7 +2625,7 @@ sub setup_mtn_object($$) __("Your version of Monotone does not support\n" . "suspend certificates. I will adjusted your\n" . "preferences accordingly.")); - $dialog->run(); + $wm->allow_input(sub { $dialog->run(); }); $dialog->destroy(); $user_preferences->{show_suspended} = 0; eval @@ -2639,7 +2641,7 @@ sub setup_mtn_object($$) "warning", "close", __("Your preferences could not be saved:\n") . $@); - $dialog->run(); + $wm->allow_input(sub { $dialog->run(); }); $dialog->destroy(); } } @@ -2712,19 +2714,22 @@ sub mtn_error_handler($$) if ($severity == MTN_SEVERITY_WARNING) { - $dialog = Gtk2::MessageDialog->new_with_markup - (undef, - ["modal"], - "warning", - "close", - __x("Problem with monotone request, got:\n" - . "{error_message}\n" - . "This should not be happening!", - error_message => Glib::Markup::escape_text($message))); - $wm->allow_input(sub { $dialog->run(); }); - $dialog->destroy(); - $wm->reset_state(); - die($message); + if (! $suppress_mtn_warnings) + { + $dialog = Gtk2::MessageDialog->new_with_markup + (undef, + ["modal"], + "warning", + "close", + __x("Problem with monotone request, got:\n" + . "{error_message}\n" + . "This should not be happening!", + error_message => Glib::Markup::escape_text($message))); + $wm->allow_input(sub { $dialog->run(); }); + $dialog->destroy(); + $wm->reset_state(); + die($message); + } } else {