2012-07-09 20:48:27 +00:00
|
|
|
/*
|
|
|
|
* This file is part of gitg
|
|
|
|
*
|
2015-08-25 16:32:27 +00:00
|
|
|
* Copyright (C) 2015 - Jesse van den Kieboom
|
2012-07-09 20:48:27 +00:00
|
|
|
*
|
|
|
|
* gitg is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* gitg is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with gitg. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
[GtkTemplate( ui = "/org/gnome/gitg/ui/gitg-diff-view.ui" )]
|
2015-08-25 19:13:41 +00:00
|
|
|
public class Gitg.DiffView : Gtk.Grid
|
2012-07-09 20:48:27 +00:00
|
|
|
{
|
2015-08-25 16:32:27 +00:00
|
|
|
[GtkChild( name = "commit_details" )]
|
2021-02-22 11:50:43 +00:00
|
|
|
private unowned Gitg.DiffViewCommitDetails d_commit_details;
|
2013-12-31 14:17:20 +00:00
|
|
|
|
2015-08-27 17:31:41 +00:00
|
|
|
[GtkChild( name = "scrolledwindow" )]
|
2021-02-22 11:50:43 +00:00
|
|
|
private unowned Gtk.ScrolledWindow d_scrolledwindow;
|
2015-08-27 17:31:41 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
[GtkChild( name = "grid_files" )]
|
2021-02-22 11:50:43 +00:00
|
|
|
private unowned Gtk.Grid d_grid_files;
|
2013-12-31 14:17:20 +00:00
|
|
|
|
2015-12-30 22:29:19 +00:00
|
|
|
[GtkChild( name = "event_box" )]
|
2021-02-22 11:50:43 +00:00
|
|
|
private unowned Gtk.EventBox d_event_box;
|
2015-12-30 22:29:19 +00:00
|
|
|
|
|
|
|
[GtkChild( name = "revealer_options" )]
|
2021-02-22 11:50:43 +00:00
|
|
|
private unowned Gtk.Revealer d_revealer_options;
|
2015-12-30 22:29:19 +00:00
|
|
|
|
|
|
|
[GtkChild( name = "diff_view_options" )]
|
2021-02-22 11:50:43 +00:00
|
|
|
private unowned DiffViewOptions d_diff_view_options;
|
2015-12-30 22:29:19 +00:00
|
|
|
|
2016-08-19 07:01:53 +00:00
|
|
|
[GtkChild( name = "text_view_message" )]
|
2021-02-22 11:50:43 +00:00
|
|
|
private unowned Gtk.TextView d_text_view_message;
|
2016-08-19 07:01:53 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
private Ggit.Diff? d_diff;
|
|
|
|
private Commit? d_commit;
|
|
|
|
private Ggit.DiffOptions? d_options;
|
2015-12-22 20:46:43 +00:00
|
|
|
private Cancellable d_cancellable;
|
|
|
|
private ulong d_expanded_notify;
|
|
|
|
private ulong d_parent_commit_notify;
|
|
|
|
private bool d_changes_inline;
|
2013-12-31 14:17:20 +00:00
|
|
|
|
2019-05-19 22:30:15 +00:00
|
|
|
Gdk.RGBA d_color_link;
|
|
|
|
Gdk.RGBA color_hovered_link;
|
|
|
|
bool hovering_over_link = false;
|
|
|
|
Gtk.TextTag hover_tag = null;
|
|
|
|
|
2015-12-30 22:29:19 +00:00
|
|
|
private uint d_reveal_options_timeout;
|
|
|
|
private uint d_unreveal_options_timeout;
|
|
|
|
|
2016-01-10 12:24:33 +00:00
|
|
|
private static Gee.HashSet<string> s_image_mime_types;
|
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
public Ggit.DiffOptions options
|
|
|
|
{
|
|
|
|
get
|
2014-07-10 17:56:24 +00:00
|
|
|
{
|
2015-08-25 16:32:27 +00:00
|
|
|
if (d_options == null)
|
2014-07-10 17:56:24 +00:00
|
|
|
{
|
2015-08-25 16:32:27 +00:00
|
|
|
d_options = new Ggit.DiffOptions();
|
2014-07-10 17:56:24 +00:00
|
|
|
}
|
2014-07-10 14:53:55 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
return d_options;
|
2014-06-30 20:01:30 +00:00
|
|
|
}
|
2015-08-25 16:32:27 +00:00
|
|
|
}
|
2012-07-09 20:48:27 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
public bool has_selection
|
|
|
|
{
|
2015-12-22 20:46:43 +00:00
|
|
|
get; private set;
|
2015-08-25 16:32:27 +00:00
|
|
|
}
|
2013-12-31 14:17:20 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
public Ggit.Diff? diff
|
|
|
|
{
|
|
|
|
get { return d_diff; }
|
|
|
|
set
|
2012-07-09 20:48:27 +00:00
|
|
|
{
|
2015-12-22 20:46:43 +00:00
|
|
|
if (d_diff != value)
|
|
|
|
{
|
|
|
|
d_diff = value;
|
|
|
|
d_commit = null;
|
|
|
|
}
|
2012-07-11 06:44:23 +00:00
|
|
|
|
2015-12-31 11:32:42 +00:00
|
|
|
update(false);
|
2012-07-09 20:48:27 +00:00
|
|
|
}
|
2015-08-25 16:32:27 +00:00
|
|
|
}
|
2012-07-09 20:48:27 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
public Commit? commit
|
|
|
|
{
|
|
|
|
get { return d_commit; }
|
|
|
|
set
|
2015-08-09 18:11:47 +00:00
|
|
|
{
|
2015-08-25 16:32:27 +00:00
|
|
|
if (d_commit != value)
|
2015-08-09 18:11:47 +00:00
|
|
|
{
|
2015-08-25 16:32:27 +00:00
|
|
|
d_commit = value;
|
|
|
|
d_diff = null;
|
2015-08-09 18:11:47 +00:00
|
|
|
}
|
2015-07-31 06:47:59 +00:00
|
|
|
|
2015-12-31 11:32:42 +00:00
|
|
|
update(false);
|
2015-07-31 06:47:59 +00:00
|
|
|
}
|
2015-08-25 16:32:27 +00:00
|
|
|
}
|
2015-07-31 06:47:59 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
public virtual signal void options_changed()
|
|
|
|
{
|
|
|
|
if (d_commit != null)
|
2014-07-10 14:27:39 +00:00
|
|
|
{
|
2015-12-31 11:32:42 +00:00
|
|
|
update(true);
|
2014-07-10 14:27:39 +00:00
|
|
|
}
|
2015-08-25 16:32:27 +00:00
|
|
|
}
|
2013-07-03 14:37:58 +00:00
|
|
|
|
2015-12-30 22:29:19 +00:00
|
|
|
public bool wrap_lines { get; construct set; default = true; }
|
2015-08-25 16:32:27 +00:00
|
|
|
public bool staged { get; set; default = false; }
|
|
|
|
public bool unstaged { get; set; default = false; }
|
|
|
|
public bool show_parents { get; set; default = false; }
|
2015-12-22 20:46:43 +00:00
|
|
|
public bool default_collapse_all { get; construct set; default = true; }
|
|
|
|
public bool use_gravatar { get; construct set; default = true; }
|
|
|
|
public int tab_width { get; construct set; default = 4; }
|
|
|
|
public bool handle_selection { get; construct set; default = false; }
|
2015-12-22 23:12:45 +00:00
|
|
|
public bool highlight { get; construct set; default = true; }
|
2019-05-19 22:30:15 +00:00
|
|
|
|
|
|
|
private Repository? d_repository;
|
|
|
|
|
2021-12-27 09:10:33 +00:00
|
|
|
private GLib.Regex regex_custom_links = /gitg\.custom-link\.(.+)\.regex/;
|
|
|
|
|
2019-05-19 22:30:15 +00:00
|
|
|
public Repository? repository {
|
|
|
|
get { return d_repository; }
|
|
|
|
set {
|
|
|
|
d_repository = value;
|
2019-06-21 07:51:44 +00:00
|
|
|
if (d_repository!=null)
|
|
|
|
{
|
2021-12-27 09:10:33 +00:00
|
|
|
d_commit_details.repository = d_repository;
|
2019-06-21 07:51:44 +00:00
|
|
|
}
|
2019-05-19 22:30:15 +00:00
|
|
|
}
|
|
|
|
}
|
2015-12-22 23:59:48 +00:00
|
|
|
public bool new_is_workdir { get; set; }
|
2019-05-19 22:30:15 +00:00
|
|
|
|
|
|
|
private GLib.Regex regex_url = /\w+:(\/?\/?)[^\s]+/;
|
2014-06-30 20:02:23 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
private bool flag_get(Ggit.DiffOption f)
|
|
|
|
{
|
|
|
|
return (options.flags & f) != 0;
|
|
|
|
}
|
2014-01-05 20:08:31 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
private void flag_set(Ggit.DiffOption f, bool val)
|
|
|
|
{
|
|
|
|
var flags = options.flags;
|
2012-07-09 20:48:27 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
if (val)
|
2013-07-03 14:37:58 +00:00
|
|
|
{
|
2015-08-25 16:32:27 +00:00
|
|
|
flags |= f;
|
2013-07-03 14:37:58 +00:00
|
|
|
}
|
2015-08-25 16:32:27 +00:00
|
|
|
else
|
2012-08-17 09:19:35 +00:00
|
|
|
{
|
2015-08-25 16:32:27 +00:00
|
|
|
flags &= ~f;
|
2012-08-17 09:19:35 +00:00
|
|
|
}
|
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
if (flags != options.flags)
|
2014-01-05 20:08:31 +00:00
|
|
|
{
|
2015-08-25 16:32:27 +00:00
|
|
|
options.flags = flags;
|
|
|
|
options_changed();
|
2014-01-05 20:08:31 +00:00
|
|
|
}
|
2015-08-25 16:32:27 +00:00
|
|
|
}
|
2014-01-05 20:08:31 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
public bool ignore_whitespace
|
|
|
|
{
|
|
|
|
get { return flag_get(Ggit.DiffOption.IGNORE_WHITESPACE); }
|
|
|
|
set { flag_set(Ggit.DiffOption.IGNORE_WHITESPACE, value); }
|
|
|
|
}
|
2012-10-30 21:21:10 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
public bool changes_inline
|
|
|
|
{
|
|
|
|
get { return d_changes_inline; }
|
|
|
|
set
|
2012-08-17 09:19:35 +00:00
|
|
|
{
|
2015-08-25 16:32:27 +00:00
|
|
|
if (d_changes_inline != value)
|
2013-03-01 23:33:29 +00:00
|
|
|
{
|
2015-08-25 16:32:27 +00:00
|
|
|
d_changes_inline = value;
|
2013-08-20 18:50:06 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
// TODO
|
|
|
|
//options_changed();
|
2013-03-01 23:33:29 +00:00
|
|
|
}
|
2012-08-17 09:19:35 +00:00
|
|
|
}
|
2015-08-25 16:32:27 +00:00
|
|
|
}
|
2012-08-17 09:19:35 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
public int context_lines
|
|
|
|
{
|
|
|
|
get { return options.n_context_lines; }
|
2012-07-17 09:46:17 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
construct set
|
2014-01-08 13:32:13 +00:00
|
|
|
{
|
2015-08-25 16:32:27 +00:00
|
|
|
if (options.n_context_lines != value)
|
2014-01-08 13:32:13 +00:00
|
|
|
{
|
2015-08-25 16:32:27 +00:00
|
|
|
options.n_context_lines = value;
|
|
|
|
options.n_interhunk_lines = value;
|
2014-01-08 13:32:13 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
options_changed();
|
2014-01-08 13:32:13 +00:00
|
|
|
}
|
|
|
|
}
|
2015-08-25 16:32:27 +00:00
|
|
|
}
|
2012-07-09 20:48:27 +00:00
|
|
|
|
2015-08-26 17:54:35 +00:00
|
|
|
protected override void constructed()
|
|
|
|
{
|
|
|
|
d_expanded_notify = d_commit_details.notify["expanded"].connect(update_expanded_files);
|
2015-11-08 19:54:48 +00:00
|
|
|
d_parent_commit_notify = d_commit_details.notify["parent-commit"].connect(parent_commit_changed);
|
2015-12-22 20:46:43 +00:00
|
|
|
|
|
|
|
bind_property("use-gravatar", d_commit_details, "use-gravatar", BindingFlags.SYNC_CREATE);
|
2019-05-19 22:30:15 +00:00
|
|
|
d_text_view_message.event_after.connect (on_event_after);
|
|
|
|
d_text_view_message.key_press_event.connect (on_key_press);
|
|
|
|
d_text_view_message.motion_notify_event.connect (on_motion_notify_event);
|
|
|
|
d_text_view_message.has_tooltip = true;
|
|
|
|
d_text_view_message.query_tooltip.connect (on_query_tooltip_event);
|
|
|
|
d_text_view_message.style_updated.connect (load_colors_from_theme);
|
|
|
|
|
|
|
|
load_colors_from_theme(d_text_view_message);
|
2015-12-30 22:29:19 +00:00
|
|
|
|
|
|
|
d_event_box.motion_notify_event.connect(motion_notify_event_on_event_box);
|
|
|
|
d_diff_view_options.view = this;
|
2015-11-08 19:54:48 +00:00
|
|
|
}
|
|
|
|
|
2016-08-18 11:58:07 +00:00
|
|
|
public override void dispose()
|
|
|
|
{
|
|
|
|
if (d_cancellable != null)
|
|
|
|
{
|
|
|
|
d_cancellable.cancel();
|
|
|
|
}
|
|
|
|
|
|
|
|
base.dispose();
|
|
|
|
}
|
|
|
|
|
2015-11-08 19:54:48 +00:00
|
|
|
private void parent_commit_changed()
|
|
|
|
{
|
2015-12-31 11:32:42 +00:00
|
|
|
update(false);
|
2015-08-26 17:54:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void update_expanded_files()
|
|
|
|
{
|
|
|
|
var expanded = d_commit_details.expanded;
|
|
|
|
|
|
|
|
foreach (var file in d_grid_files.get_children())
|
|
|
|
{
|
2021-02-22 12:08:08 +00:00
|
|
|
((Gitg.DiffViewFile) file).expanded = expanded;
|
2015-08-26 17:54:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-19 07:01:53 +00:00
|
|
|
private static Regex s_message_regexp;
|
|
|
|
|
|
|
|
static construct
|
|
|
|
{
|
2016-01-10 12:24:33 +00:00
|
|
|
s_image_mime_types = new Gee.HashSet<string>();
|
|
|
|
|
|
|
|
foreach (var format in Gdk.Pixbuf.get_formats())
|
|
|
|
{
|
|
|
|
foreach (var mime_type in format.get_mime_types())
|
|
|
|
{
|
|
|
|
s_image_mime_types.add(mime_type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-19 07:01:53 +00:00
|
|
|
try
|
|
|
|
{
|
2018-10-14 16:18:01 +00:00
|
|
|
s_message_regexp = new Regex(".*(\\R|\\s)*(?P<message>(?:.|\\R)*?)\\s*$");
|
2016-08-19 07:01:53 +00:00
|
|
|
} catch (Error e) { stderr.printf(@"Failed to compile regex: $(e.message)\n"); }
|
|
|
|
}
|
|
|
|
|
2018-04-24 08:07:57 +00:00
|
|
|
construct
|
|
|
|
{
|
|
|
|
context_lines = 3;
|
|
|
|
}
|
|
|
|
|
2016-08-19 07:01:53 +00:00
|
|
|
private string message_without_subject(Commit commit)
|
|
|
|
{
|
|
|
|
var message = commit.get_message();
|
|
|
|
MatchInfo minfo;
|
|
|
|
|
|
|
|
if (s_message_regexp.match(message, 0, out minfo))
|
|
|
|
{
|
|
|
|
return minfo.fetch_named("message");
|
|
|
|
}
|
|
|
|
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2019-05-19 22:30:15 +00:00
|
|
|
private bool on_query_tooltip_event(int x, int y, bool keyboard_tooltip, Gtk.Tooltip tooltip)
|
|
|
|
{
|
|
|
|
Gtk.TextIter iter;
|
|
|
|
|
|
|
|
if (d_text_view_message.get_iter_at_location (out iter, x, y))
|
|
|
|
{
|
|
|
|
var tags = iter.get_tags ();
|
|
|
|
foreach (Gtk.TextTag tag in tags)
|
|
|
|
{
|
|
|
|
if (tag.get_data<string>("type") == "url" && tag.get_data<bool>("is_custom_link"))
|
|
|
|
{
|
|
|
|
string url = tag.get_data<string>("url");
|
|
|
|
tooltip.set_text (url);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void apply_link_tags(Gtk.TextBuffer buffer, Regex regex, string? replacement, Gdk.RGBA custom_color_link, bool is_custom_color, bool is_custom_link)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
GLib.MatchInfo matchInfo;
|
|
|
|
|
|
|
|
var buffer_text = buffer.text;
|
|
|
|
regex.match (buffer_text, 0, out matchInfo);
|
|
|
|
|
|
|
|
while (matchInfo.matches ())
|
|
|
|
{
|
|
|
|
Gtk.TextIter start, end;
|
|
|
|
int start_pos, end_pos;
|
|
|
|
string text = matchInfo.fetch(0);
|
|
|
|
matchInfo.fetch_pos (0, out start_pos, out end_pos);
|
|
|
|
buffer.get_iter_at_offset(out start, start_pos);
|
|
|
|
buffer.get_iter_at_offset(out end, end_pos);
|
|
|
|
|
|
|
|
var tag = buffer.create_tag(null, "underline", Pango.Underline.SINGLE);
|
|
|
|
tag.foreground_rgba = custom_color_link;
|
|
|
|
tag.set_data("type", "url");
|
|
|
|
tag.set_data<Gdk.RGBA?>("color_link", custom_color_link);
|
|
|
|
if (replacement != null)
|
|
|
|
{
|
|
|
|
text = regex.replace(text, text.length, 0, replacement);
|
|
|
|
}
|
|
|
|
tag.set_data("url", text);
|
|
|
|
tag.set_data("is_custom_color_link", is_custom_color);
|
|
|
|
tag.set_data("is_custom_link", is_custom_link);
|
|
|
|
buffer.apply_tag(tag, start, end);
|
|
|
|
|
|
|
|
matchInfo.next();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch(Error e)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void load_colors_from_theme(Gtk.Widget widget)
|
|
|
|
{
|
|
|
|
Gtk.TextView textview = (Gtk.TextView)widget;
|
|
|
|
Gtk.StyleContext context = textview.get_style_context ();
|
|
|
|
|
|
|
|
context.save ();
|
|
|
|
context.set_state (Gtk.StateFlags.LINK);
|
|
|
|
d_color_link = context.get_color (context.get_state ());
|
|
|
|
|
|
|
|
context.set_state (Gtk.StateFlags.LINK | Gtk.StateFlags.PRELIGHT);
|
|
|
|
color_hovered_link = context.get_color (context.get_state ());
|
|
|
|
context.restore ();
|
|
|
|
|
|
|
|
textview.buffer.tag_table.foreach ((tag) =>
|
|
|
|
{
|
|
|
|
if (!tag.get_data<bool>("is_custom_color_link"))
|
|
|
|
{
|
|
|
|
tag.set_data<Gdk.RGBA?>("color_link", d_color_link);
|
|
|
|
tag.foreground_rgba = d_color_link;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
private bool on_key_press (Gtk.Widget widget, Gdk.EventKey evt)
|
|
|
|
{
|
|
|
|
if (evt.keyval == Gdk.Key.Return || evt.keyval == Gdk.Key.KP_Enter)
|
|
|
|
{
|
|
|
|
|
|
|
|
Gtk.TextIter iter;
|
|
|
|
Gtk.TextView textview = (Gtk.TextView) widget;
|
|
|
|
textview.buffer.get_iter_at_mark(out iter, textview.buffer.get_insert());
|
|
|
|
|
|
|
|
follow_if_link (widget, iter);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void follow_if_link(Gtk.Widget texview, Gtk.TextIter iter)
|
|
|
|
{
|
|
|
|
var tags = iter.get_tags ();
|
|
|
|
foreach (Gtk.TextTag tag in tags)
|
|
|
|
{
|
|
|
|
if (tag.get_data<string>("type") == "url")
|
|
|
|
{
|
|
|
|
string url = tag.get_data<string>("url");
|
|
|
|
try
|
|
|
|
{
|
|
|
|
GLib.AppInfo.launch_default_for_uri(url, null);
|
|
|
|
}
|
|
|
|
catch(Error e)
|
|
|
|
{
|
|
|
|
warning ("Cannot open %s: %s", url, e.message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
private void on_event_after (Gtk.Widget widget, Gdk.Event evt)
|
|
|
|
{
|
|
|
|
|
|
|
|
Gtk.TextIter start, end, iter;
|
|
|
|
Gtk.TextBuffer buffer;
|
|
|
|
double ex, ey;
|
|
|
|
int x, y;
|
|
|
|
|
|
|
|
if (evt.type == Gdk.EventType.BUTTON_RELEASE)
|
|
|
|
{
|
|
|
|
Gdk.EventButton event;
|
|
|
|
|
|
|
|
event = (Gdk.EventButton)evt;
|
|
|
|
if (event.button != Gdk.BUTTON_PRIMARY)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ex = event.x;
|
|
|
|
ey = event.y;
|
|
|
|
}
|
|
|
|
else if (evt.type == Gdk.EventType.TOUCH_END)
|
|
|
|
{
|
|
|
|
Gdk.EventTouch event;
|
|
|
|
|
|
|
|
event = (Gdk.EventTouch)evt;
|
|
|
|
|
|
|
|
ex = event.x;
|
|
|
|
ey = event.y;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Gtk.TextView textview = (Gtk.TextView)widget;
|
|
|
|
buffer = textview.buffer;
|
|
|
|
|
|
|
|
/* we shouldn't follow a link if the user has selected something */
|
|
|
|
buffer.get_selection_bounds (out start, out end);
|
|
|
|
if (start.get_offset () != end.get_offset ())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
textview.window_to_buffer_coords (Gtk.TextWindowType.WIDGET,(int)ex, (int)ey, out x, out y);
|
|
|
|
|
|
|
|
if (textview.get_iter_at_location (out iter, x, y))
|
|
|
|
{
|
|
|
|
follow_if_link (textview, iter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private bool on_motion_notify_event (Gtk.Widget widget, Gdk.EventMotion evt)
|
|
|
|
{
|
|
|
|
int x, y;
|
|
|
|
|
|
|
|
Gtk.TextView textview = ((Gtk.TextView)widget);
|
|
|
|
|
|
|
|
textview.window_to_buffer_coords (Gtk.TextWindowType.WIDGET,(int)evt.x, (int)evt.y, out x, out y);
|
|
|
|
|
|
|
|
Gtk.TextIter iter;
|
|
|
|
bool hovering = false;
|
|
|
|
|
|
|
|
if (textview.get_iter_at_location (out iter, x, y))
|
|
|
|
{
|
|
|
|
var tags = iter.get_tags ();
|
|
|
|
foreach (Gtk.TextTag tag in tags)
|
|
|
|
{
|
|
|
|
if (tag.get_data<string>("type") == "url")
|
|
|
|
{
|
|
|
|
hovering = true;
|
|
|
|
if (hover_tag != null && hover_tag != tag)
|
|
|
|
{
|
|
|
|
restore_tag_color_link (hover_tag);
|
|
|
|
hovering_over_link = false;
|
|
|
|
}
|
|
|
|
hover_tag = tag;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hovering != hovering_over_link)
|
|
|
|
{
|
|
|
|
hovering_over_link = hovering;
|
|
|
|
|
|
|
|
Gdk.Display display = textview.get_display();
|
|
|
|
Gdk.Cursor hand_cursor = new Gdk.Cursor.from_name (display, "pointer");
|
|
|
|
Gdk.Cursor regular_cursor = new Gdk.Cursor.from_name (display, "text");
|
|
|
|
|
|
|
|
Gdk.Window window = textview.get_window (Gtk.TextWindowType.TEXT);
|
|
|
|
if (hovering_over_link)
|
|
|
|
{
|
|
|
|
window.set_cursor (hand_cursor);
|
|
|
|
if (hover_tag != null)
|
|
|
|
{
|
|
|
|
hover_tag.foreground_rgba = color_hovered_link;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
window.set_cursor (regular_cursor);
|
|
|
|
if (hover_tag != null)
|
|
|
|
{
|
|
|
|
restore_tag_color_link (hover_tag);
|
|
|
|
hover_tag = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void restore_tag_color_link (Gtk.TextTag tag)
|
|
|
|
{
|
|
|
|
Gdk.RGBA? color = tag.get_data<Gdk.RGBA?>("color_link");
|
|
|
|
tag.foreground_rgba = color;
|
|
|
|
}
|
|
|
|
|
2015-12-31 11:32:42 +00:00
|
|
|
private void update(bool preserve_expanded)
|
2015-08-25 16:32:27 +00:00
|
|
|
{
|
2019-05-19 22:30:15 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
// If both `d_diff` and `d_commit` are null, clear
|
|
|
|
// the diff content
|
|
|
|
if (d_diff == null && d_commit == null)
|
2015-08-09 18:11:47 +00:00
|
|
|
{
|
2015-08-27 17:31:41 +00:00
|
|
|
d_commit_details.hide();
|
|
|
|
d_scrolledwindow.hide();
|
2015-08-25 16:32:27 +00:00
|
|
|
return;
|
2015-08-09 18:11:47 +00:00
|
|
|
}
|
|
|
|
|
2015-08-27 17:31:41 +00:00
|
|
|
d_commit_details.show();
|
|
|
|
d_scrolledwindow.show();
|
2014-07-10 17:13:16 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
// Cancel running operations
|
|
|
|
d_cancellable.cancel();
|
|
|
|
d_cancellable = new Cancellable();
|
2014-07-10 17:13:16 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
if (d_commit != null)
|
2012-07-09 20:48:27 +00:00
|
|
|
{
|
2015-11-08 19:54:48 +00:00
|
|
|
SignalHandler.block(d_commit_details, d_parent_commit_notify);
|
|
|
|
d_commit_details.commit = d_commit;
|
|
|
|
SignalHandler.unblock(d_commit_details, d_parent_commit_notify);
|
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
int parent = 0;
|
|
|
|
var parents = d_commit.get_parents();
|
2012-07-09 20:48:27 +00:00
|
|
|
|
2015-11-08 19:54:48 +00:00
|
|
|
var parent_commit = d_commit_details.parent_commit;
|
|
|
|
|
|
|
|
if (parent_commit != null)
|
2013-07-03 16:50:18 +00:00
|
|
|
{
|
2015-08-25 16:32:27 +00:00
|
|
|
for (var i = 0; i < parents.size; i++)
|
2014-12-16 07:23:30 +00:00
|
|
|
{
|
2015-08-25 16:32:27 +00:00
|
|
|
var id = parents.get_id(i);
|
2014-12-16 07:23:30 +00:00
|
|
|
|
2015-11-08 19:54:48 +00:00
|
|
|
if (id.equal(parent_commit.get_id()))
|
2015-08-25 16:32:27 +00:00
|
|
|
{
|
|
|
|
parent = i;
|
|
|
|
break;
|
2014-12-16 07:23:30 +00:00
|
|
|
}
|
|
|
|
}
|
2012-07-11 06:44:23 +00:00
|
|
|
}
|
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
d_diff = d_commit.get_diff(options, parent);
|
|
|
|
d_commit_details.show();
|
2016-08-19 07:01:53 +00:00
|
|
|
|
|
|
|
var message = message_without_subject(d_commit);
|
|
|
|
|
|
|
|
d_text_view_message.buffer.set_text(message);
|
2019-05-19 22:30:15 +00:00
|
|
|
var buffer = d_text_view_message.get_buffer();
|
|
|
|
|
|
|
|
apply_link_tags(buffer, regex_url, null, d_color_link, false, false);
|
|
|
|
|
2021-12-27 09:10:33 +00:00
|
|
|
parse_smart_text(buffer);
|
2019-05-19 22:30:15 +00:00
|
|
|
|
2016-08-19 07:01:53 +00:00
|
|
|
d_text_view_message.visible = (message != "");
|
2012-07-09 20:48:27 +00:00
|
|
|
}
|
2015-08-25 16:32:27 +00:00
|
|
|
else
|
2013-12-31 14:17:20 +00:00
|
|
|
{
|
2015-08-25 16:32:27 +00:00
|
|
|
d_commit_details.commit = null;
|
|
|
|
d_commit_details.hide();
|
2016-08-19 07:01:53 +00:00
|
|
|
|
|
|
|
d_text_view_message.hide();
|
2013-12-31 14:17:20 +00:00
|
|
|
}
|
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
if (d_diff != null)
|
2014-12-14 19:16:00 +00:00
|
|
|
{
|
2015-12-31 11:32:42 +00:00
|
|
|
update_diff(d_diff, preserve_expanded, d_cancellable);
|
2014-12-16 07:23:30 +00:00
|
|
|
}
|
2015-08-25 16:32:27 +00:00
|
|
|
}
|
2014-12-16 07:23:30 +00:00
|
|
|
|
2021-12-27 09:10:33 +00:00
|
|
|
private void parse_smart_text(Gtk.TextBuffer buffer)
|
2019-05-19 22:30:15 +00:00
|
|
|
{
|
2021-12-27 09:10:33 +00:00
|
|
|
if (repository != null)
|
2019-05-19 22:30:15 +00:00
|
|
|
{
|
2021-12-27 09:10:33 +00:00
|
|
|
var conf = repository.get_config().snapshot();
|
2019-06-21 07:51:44 +00:00
|
|
|
try
|
2019-05-19 22:30:15 +00:00
|
|
|
{
|
2021-12-27 09:10:33 +00:00
|
|
|
conf.match_foreach(regex_custom_links, (match_info, value) => {
|
|
|
|
string group = match_info.fetch(1);
|
|
|
|
debug ("found custom-link group: %s", group);
|
|
|
|
string custom_link_regexp = value;
|
|
|
|
string replacement_key = "gitg.custom-link.%s.replacement".printf(group);
|
|
|
|
try
|
2019-05-19 22:30:15 +00:00
|
|
|
{
|
2021-12-27 09:10:33 +00:00
|
|
|
string custom_link_replacement = conf.get_string(replacement_key);
|
|
|
|
string color_key = "gitg.custom-link.%s.color".printf(group);
|
|
|
|
string custom_color = conf.get_string(color_key);
|
|
|
|
Gdk.RGBA color = d_color_link;
|
|
|
|
bool is_custom_color = custom_color != null;
|
|
|
|
if (is_custom_color)
|
2019-05-19 22:30:15 +00:00
|
|
|
{
|
2021-12-27 09:10:33 +00:00
|
|
|
color = Gdk.RGBA();
|
|
|
|
color.parse(custom_color);
|
2019-05-19 22:30:15 +00:00
|
|
|
}
|
2021-12-27 09:10:33 +00:00
|
|
|
apply_link_tags(buffer, new Regex (custom_link_regexp), custom_link_replacement, color, is_custom_color, true);
|
|
|
|
} catch (Error e)
|
|
|
|
{
|
|
|
|
warning ("Cannot read git config: %s", e.message);
|
2019-05-19 22:30:15 +00:00
|
|
|
}
|
2021-12-27 09:10:33 +00:00
|
|
|
return 0;
|
|
|
|
});
|
2019-06-21 07:51:44 +00:00
|
|
|
} catch (Error e)
|
|
|
|
{
|
2021-12-27 09:10:33 +00:00
|
|
|
warning ("Cannot read git config: %s", e.message);
|
2019-05-19 22:30:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-26 17:54:35 +00:00
|
|
|
private void auto_change_expanded(bool expanded)
|
2015-08-25 16:32:27 +00:00
|
|
|
{
|
2015-08-26 17:54:35 +00:00
|
|
|
SignalHandler.block(d_commit_details, d_expanded_notify);
|
|
|
|
d_commit_details.expanded = expanded;
|
|
|
|
SignalHandler.unblock(d_commit_details, d_expanded_notify);
|
|
|
|
}
|
2015-08-25 19:42:41 +00:00
|
|
|
|
2015-12-18 15:04:52 +00:00
|
|
|
private void on_selection_changed()
|
|
|
|
{
|
|
|
|
bool something_selected = false;
|
|
|
|
|
|
|
|
foreach (var file in d_grid_files.get_children())
|
|
|
|
{
|
2021-11-19 22:47:12 +00:00
|
|
|
if (((Gitg.DiffViewFile) file).has_selection())
|
2015-12-18 15:04:52 +00:00
|
|
|
{
|
|
|
|
something_selected = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-22 20:46:43 +00:00
|
|
|
if (has_selection != something_selected)
|
2015-12-18 15:04:52 +00:00
|
|
|
{
|
2015-12-22 20:46:43 +00:00
|
|
|
has_selection = something_selected;
|
2015-12-18 15:04:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-10 12:24:33 +00:00
|
|
|
private string? primary_path(Ggit.DiffDelta delta)
|
2015-12-31 11:32:42 +00:00
|
|
|
{
|
2016-01-10 12:24:33 +00:00
|
|
|
var path = delta.get_old_file().get_path();
|
2015-12-31 11:32:42 +00:00
|
|
|
|
|
|
|
if (path == null)
|
|
|
|
{
|
2016-01-10 12:24:33 +00:00
|
|
|
path = delta.get_new_file().get_path();
|
2015-12-31 11:32:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
2016-08-16 15:59:27 +00:00
|
|
|
private delegate void Anon();
|
|
|
|
|
|
|
|
private string key_for_delta(Ggit.DiffDelta delta)
|
|
|
|
{
|
|
|
|
var new_file = delta.get_new_file();
|
|
|
|
var new_path = new_file.get_path();
|
|
|
|
|
|
|
|
if (new_path != null)
|
|
|
|
{
|
|
|
|
return @"path:$(new_path)";
|
|
|
|
}
|
|
|
|
|
|
|
|
var old_file = delta.get_old_file();
|
|
|
|
var old_path = old_file.get_path();
|
|
|
|
|
|
|
|
if (old_path != null)
|
|
|
|
{
|
|
|
|
return @"path:$(old_path)";
|
|
|
|
}
|
|
|
|
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2015-12-31 11:32:42 +00:00
|
|
|
private void update_diff(Ggit.Diff diff, bool preserve_expanded, Cancellable? cancellable)
|
2016-08-16 15:59:27 +00:00
|
|
|
{
|
|
|
|
var nqueries = 0;
|
|
|
|
var finished = false;
|
|
|
|
var infomap = new Gee.HashMap<string, DiffViewFileInfo>();
|
|
|
|
|
|
|
|
Anon check_finish = () => {
|
|
|
|
if (nqueries == 0 && finished && (cancellable == null || !cancellable.is_cancelled()))
|
|
|
|
{
|
|
|
|
finished = false;
|
|
|
|
update_diff_hunks(diff, preserve_expanded, infomap, cancellable);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Collect file info asynchronously first
|
|
|
|
for (var i = 0; i < diff.get_num_deltas(); i++)
|
|
|
|
{
|
|
|
|
var delta = diff.get_delta(i);
|
|
|
|
var info = new DiffViewFileInfo(repository, delta, new_is_workdir);
|
|
|
|
|
|
|
|
nqueries++;
|
|
|
|
|
|
|
|
info.query.begin(cancellable, (obj, res) => {
|
|
|
|
info.query.end(res);
|
|
|
|
|
|
|
|
infomap[key_for_delta(delta)] = info;
|
|
|
|
|
|
|
|
nqueries--;
|
|
|
|
|
|
|
|
check_finish();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
finished = true;
|
|
|
|
check_finish();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void update_diff_hunks(Ggit.Diff diff, bool preserve_expanded, Gee.HashMap<string, DiffViewFileInfo> infomap, Cancellable? cancellable)
|
2015-08-26 17:54:35 +00:00
|
|
|
{
|
|
|
|
var files = new Gee.ArrayList<Gitg.DiffViewFile>();
|
2016-01-03 19:46:23 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
Gitg.DiffViewFile? current_file = null;
|
|
|
|
Ggit.DiffHunk? current_hunk = null;
|
|
|
|
Gee.ArrayList<Ggit.DiffLine>? current_lines = null;
|
2016-08-16 15:59:27 +00:00
|
|
|
var current_is_binary = false;
|
2013-12-31 14:17:20 +00:00
|
|
|
|
2015-08-25 19:42:41 +00:00
|
|
|
var maxlines = 0;
|
2015-08-27 09:34:39 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
Anon add_hunk = () => {
|
|
|
|
if (current_hunk != null)
|
|
|
|
{
|
|
|
|
current_file.add_hunk(current_hunk, current_lines);
|
2013-12-31 14:17:20 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
current_lines = null;
|
|
|
|
current_hunk = null;
|
|
|
|
}
|
|
|
|
};
|
2013-12-31 14:17:20 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
Anon add_file = () => {
|
|
|
|
add_hunk();
|
2013-12-31 14:17:20 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
if (current_file != null)
|
2013-12-31 14:17:20 +00:00
|
|
|
{
|
2015-08-25 16:32:27 +00:00
|
|
|
current_file.show();
|
2013-12-31 14:17:20 +00:00
|
|
|
|
2015-08-25 19:42:41 +00:00
|
|
|
files.add(current_file);
|
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
current_file = null;
|
|
|
|
}
|
|
|
|
};
|
2013-12-31 14:17:20 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
try
|
2013-12-31 14:17:20 +00:00
|
|
|
{
|
2015-08-25 16:32:27 +00:00
|
|
|
diff.foreach(
|
|
|
|
(delta, progress) => {
|
|
|
|
if (cancellable != null && cancellable.is_cancelled())
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
2013-12-31 14:17:20 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
add_file();
|
2013-12-31 14:17:20 +00:00
|
|
|
|
2016-08-16 15:59:27 +00:00
|
|
|
DiffViewFileInfo? info = null;
|
|
|
|
var deltakey = key_for_delta(delta);
|
|
|
|
|
|
|
|
if (infomap.has_key(deltakey))
|
|
|
|
{
|
|
|
|
info = infomap[deltakey];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
info = new DiffViewFileInfo(repository, delta, new_is_workdir);
|
|
|
|
}
|
|
|
|
|
|
|
|
current_is_binary = ((delta.get_flags() & Ggit.DiffFlag.BINARY) != 0);
|
|
|
|
|
|
|
|
// List of known binary file types that may be wrongly classified by
|
|
|
|
// libgit2 because it does not contain any null bytes in the first N
|
|
|
|
// bytes. E.g. PDF
|
|
|
|
var known_binary_files_types = new string[] {"application/pdf"};
|
|
|
|
|
|
|
|
// Ignore binary based on content type
|
|
|
|
if (info != null && info.new_file_content_type in known_binary_files_types)
|
|
|
|
{
|
|
|
|
current_is_binary = true;
|
|
|
|
}
|
|
|
|
|
2016-01-10 12:24:33 +00:00
|
|
|
string? mime_type_for_image = null;
|
|
|
|
|
|
|
|
if (info == null || info.new_file_content_type == null)
|
|
|
|
{
|
|
|
|
// Guess mime type from old file name in the case of a deleted file
|
|
|
|
var oldpath = delta.get_old_file().get_path();
|
|
|
|
|
|
|
|
if (oldpath != null)
|
|
|
|
{
|
|
|
|
bool uncertain;
|
|
|
|
var ctype = ContentType.guess(Path.get_basename(oldpath), null, out uncertain);
|
|
|
|
|
|
|
|
if (ctype != null)
|
|
|
|
{
|
|
|
|
mime_type_for_image = ContentType.get_mime_type(ctype);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mime_type_for_image = ContentType.get_mime_type(info.new_file_content_type);
|
|
|
|
}
|
|
|
|
|
2019-10-16 12:34:23 +00:00
|
|
|
bool can_diff_as_text = ContentType.is_mime_type(mime_type_for_image, "text/plain");
|
|
|
|
|
|
|
|
current_file = new Gitg.DiffViewFile(info);
|
|
|
|
|
2021-11-18 07:26:12 +00:00
|
|
|
if (mime_type_for_image != null
|
|
|
|
&& s_image_mime_types.contains(mime_type_for_image))
|
|
|
|
{
|
|
|
|
current_file.add_image_renderer();
|
|
|
|
}
|
2019-10-16 12:34:23 +00:00
|
|
|
if (can_diff_as_text)
|
2016-01-10 12:24:33 +00:00
|
|
|
{
|
2019-10-16 12:34:23 +00:00
|
|
|
current_file.add_text_renderer(handle_selection);
|
2021-11-19 22:47:12 +00:00
|
|
|
var renderer_list = current_file.renderer_list;
|
|
|
|
foreach (DiffViewFileRenderer renderer in renderer_list)
|
|
|
|
{
|
|
|
|
var renderer_text = renderer as DiffViewFileRendererTextable;
|
|
|
|
if (renderer_text != null)
|
|
|
|
{
|
|
|
|
bind_property("highlight", renderer_text, "highlight", BindingFlags.SYNC_CREATE);
|
|
|
|
bind_property("wrap-lines", renderer_text, "wrap-lines", BindingFlags.DEFAULT | BindingFlags.SYNC_CREATE);
|
|
|
|
bind_property("tab-width", renderer_text, "tab-width", BindingFlags.DEFAULT | BindingFlags.SYNC_CREATE);
|
|
|
|
renderer_text.maxlines = maxlines;
|
|
|
|
renderer_text.notify["has-selection"].connect(on_selection_changed);
|
|
|
|
}
|
|
|
|
}
|
2016-01-10 12:24:33 +00:00
|
|
|
}
|
2019-10-16 12:34:23 +00:00
|
|
|
if (current_is_binary)
|
2016-08-16 15:59:27 +00:00
|
|
|
{
|
2019-10-16 12:34:23 +00:00
|
|
|
current_file.add_binary_renderer();
|
2016-08-16 15:59:27 +00:00
|
|
|
}
|
2016-01-03 19:46:23 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
return 0;
|
|
|
|
},
|
2013-12-31 14:17:20 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
(delta, binary) => {
|
|
|
|
// FIXME: do we want to handle binary data?
|
|
|
|
if (cancellable != null && cancellable.is_cancelled())
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
2013-12-31 14:17:20 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
return 0;
|
|
|
|
},
|
2013-12-31 14:17:20 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
(delta, hunk) => {
|
|
|
|
if (cancellable != null && cancellable.is_cancelled())
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
2013-12-31 14:17:20 +00:00
|
|
|
|
2016-08-16 15:59:27 +00:00
|
|
|
if (!current_is_binary)
|
|
|
|
{
|
|
|
|
maxlines = int.max(maxlines, hunk.get_old_start() + hunk.get_old_lines());
|
|
|
|
maxlines = int.max(maxlines, hunk.get_new_start() + hunk.get_new_lines());
|
2015-08-25 19:42:41 +00:00
|
|
|
|
2016-08-16 15:59:27 +00:00
|
|
|
add_hunk();
|
2013-12-31 14:17:20 +00:00
|
|
|
|
2016-08-16 15:59:27 +00:00
|
|
|
current_hunk = hunk;
|
|
|
|
current_lines = new Gee.ArrayList<Ggit.DiffLine>();
|
|
|
|
}
|
2014-06-30 20:02:23 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
return 0;
|
|
|
|
},
|
2014-06-30 20:02:23 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
(delta, hunk, line) => {
|
|
|
|
if (cancellable != null && cancellable.is_cancelled())
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
2014-06-30 20:02:23 +00:00
|
|
|
|
2016-08-16 15:59:27 +00:00
|
|
|
if (!current_is_binary)
|
2015-08-25 16:32:27 +00:00
|
|
|
{
|
|
|
|
current_lines.add(line);
|
|
|
|
}
|
2014-06-30 20:02:23 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
);
|
|
|
|
} catch {}
|
2014-07-09 19:42:55 +00:00
|
|
|
|
2015-08-25 16:32:27 +00:00
|
|
|
add_hunk();
|
|
|
|
add_file();
|
2015-08-25 19:42:41 +00:00
|
|
|
|
2015-12-31 11:32:42 +00:00
|
|
|
var file_widgets = d_grid_files.get_children();
|
|
|
|
var was_expanded = new Gee.HashSet<string>();
|
|
|
|
|
|
|
|
foreach (var file in file_widgets)
|
|
|
|
{
|
2021-02-22 12:08:08 +00:00
|
|
|
unowned DiffViewFile f = (DiffViewFile) file;
|
2015-12-31 11:32:42 +00:00
|
|
|
|
|
|
|
if (preserve_expanded && f.expanded)
|
|
|
|
{
|
2019-10-16 12:34:23 +00:00
|
|
|
var path = primary_path(f.info.delta);
|
2015-12-31 11:32:42 +00:00
|
|
|
|
|
|
|
if (path != null)
|
|
|
|
{
|
|
|
|
was_expanded.add(path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
f.destroy();
|
|
|
|
}
|
|
|
|
|
2015-12-22 20:46:43 +00:00
|
|
|
d_commit_details.expanded = (files.size <= 1 || !default_collapse_all);
|
|
|
|
d_commit_details.expander_visible = (files.size > 1);
|
2015-08-26 17:54:35 +00:00
|
|
|
|
2015-12-21 10:06:09 +00:00
|
|
|
for (var i = 0; i < files.size; i++)
|
2015-08-25 19:42:41 +00:00
|
|
|
{
|
2015-12-21 10:06:09 +00:00
|
|
|
var file = files[i];
|
2019-10-16 12:34:23 +00:00
|
|
|
var path = primary_path(file.info.delta);
|
2015-12-21 10:06:09 +00:00
|
|
|
|
2015-12-31 11:32:42 +00:00
|
|
|
file.expanded = d_commit_details.expanded || (path != null && was_expanded.contains(path));
|
2015-08-26 17:54:35 +00:00
|
|
|
|
2015-12-21 10:06:09 +00:00
|
|
|
if (i == files.size - 1)
|
|
|
|
{
|
|
|
|
file.vexpand = true;
|
|
|
|
}
|
2016-01-04 14:04:31 +00:00
|
|
|
|
|
|
|
d_grid_files.add(file);
|
|
|
|
|
|
|
|
file.notify["expanded"].connect(auto_update_expanded);
|
2015-08-26 17:54:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void auto_update_expanded()
|
|
|
|
{
|
|
|
|
foreach (var file in d_grid_files.get_children())
|
|
|
|
{
|
2021-02-22 12:08:08 +00:00
|
|
|
if (!((Gitg.DiffViewFile) file).expanded)
|
2015-08-26 17:54:35 +00:00
|
|
|
{
|
|
|
|
auto_change_expanded(false);
|
|
|
|
return;
|
|
|
|
}
|
2015-08-25 19:42:41 +00:00
|
|
|
}
|
2015-08-26 17:54:35 +00:00
|
|
|
|
|
|
|
auto_change_expanded(true);
|
2015-08-25 16:32:27 +00:00
|
|
|
}
|
2014-07-10 17:10:38 +00:00
|
|
|
|
2019-04-06 13:50:54 +00:00
|
|
|
public PatchSet[] get_selection()
|
2015-08-25 16:32:27 +00:00
|
|
|
{
|
2019-04-06 13:50:54 +00:00
|
|
|
var ret = new PatchSet[0];
|
|
|
|
|
|
|
|
foreach (var file in d_grid_files.get_children())
|
2015-12-20 22:02:26 +00:00
|
|
|
{
|
2021-11-19 22:47:12 +00:00
|
|
|
ret += ((Gitg.DiffViewFile)file).get_selection();
|
2015-12-20 22:02:26 +00:00
|
|
|
}
|
2019-04-06 13:50:54 +00:00
|
|
|
|
|
|
|
return ret;
|
2012-07-09 20:48:27 +00:00
|
|
|
}
|
2015-08-27 17:31:54 +00:00
|
|
|
|
2015-12-30 22:29:19 +00:00
|
|
|
private void update_hide_show_options(Gdk.Window window, int ex, int ey)
|
2015-08-27 17:31:54 +00:00
|
|
|
{
|
2015-12-30 22:29:19 +00:00
|
|
|
void *data;
|
|
|
|
window.get_user_data(out data);
|
2015-08-27 17:31:54 +00:00
|
|
|
|
2015-12-30 22:29:19 +00:00
|
|
|
var w = data as Gtk.Widget;
|
2015-08-27 17:31:54 +00:00
|
|
|
|
2015-12-30 22:29:19 +00:00
|
|
|
if (w == null)
|
2015-08-27 17:31:54 +00:00
|
|
|
{
|
2015-12-30 22:29:19 +00:00
|
|
|
return;
|
2015-08-27 17:31:54 +00:00
|
|
|
}
|
|
|
|
|
2015-12-30 22:29:19 +00:00
|
|
|
int x, y;
|
|
|
|
w.translate_coordinates(d_event_box, ex, ey, out x, out y);
|
|
|
|
|
|
|
|
Gtk.Allocation alloc, revealer_alloc;
|
|
|
|
|
|
|
|
d_event_box.get_allocation(out alloc);
|
|
|
|
d_revealer_options.get_allocation(out revealer_alloc);
|
2015-08-27 17:31:54 +00:00
|
|
|
|
2016-06-05 10:23:17 +00:00
|
|
|
if (!d_revealer_options.reveal_child && y >= alloc.height - 18 && x >= alloc.width - 150 && d_reveal_options_timeout == 0)
|
2015-12-30 22:29:19 +00:00
|
|
|
{
|
|
|
|
if (d_unreveal_options_timeout != 0)
|
|
|
|
{
|
|
|
|
Source.remove(d_unreveal_options_timeout);
|
|
|
|
d_unreveal_options_timeout = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
d_reveal_options_timeout = Timeout.add(300, () => {
|
|
|
|
d_reveal_options_timeout = 0;
|
|
|
|
d_revealer_options.reveal_child = true;
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else if (d_revealer_options.reveal_child)
|
|
|
|
{
|
|
|
|
var above = (y <= alloc.height - 6 - revealer_alloc.height);
|
|
|
|
|
|
|
|
if (above && d_unreveal_options_timeout == 0)
|
|
|
|
{
|
|
|
|
if (d_reveal_options_timeout != 0)
|
|
|
|
{
|
|
|
|
Source.remove(d_reveal_options_timeout);
|
|
|
|
d_reveal_options_timeout = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
d_unreveal_options_timeout = Timeout.add(1000, () => {
|
|
|
|
d_unreveal_options_timeout = 0;
|
|
|
|
d_revealer_options.reveal_child = false;
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else if (!above && d_unreveal_options_timeout != 0)
|
|
|
|
{
|
|
|
|
Source.remove(d_unreveal_options_timeout);
|
|
|
|
d_unreveal_options_timeout = 0;
|
|
|
|
}
|
|
|
|
}
|
2015-08-27 17:31:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
[GtkCallback]
|
2015-12-30 22:29:19 +00:00
|
|
|
private bool leave_notify_event_on_event_box(Gtk.Widget widget, Gdk.EventCrossing event)
|
2015-08-27 17:31:54 +00:00
|
|
|
{
|
2015-12-30 22:29:19 +00:00
|
|
|
update_hide_show_options(event.window, (int)event.x, (int)event.y);
|
|
|
|
return false;
|
|
|
|
}
|
2015-08-27 17:31:54 +00:00
|
|
|
|
2015-12-30 22:29:19 +00:00
|
|
|
[GtkCallback]
|
|
|
|
private bool enter_notify_event_on_event_box(Gtk.Widget widget, Gdk.EventCrossing event)
|
|
|
|
{
|
|
|
|
update_hide_show_options(event.window, (int)event.x, (int)event.y);
|
2015-08-27 17:31:54 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-12-30 22:29:19 +00:00
|
|
|
[GtkCallback]
|
|
|
|
private bool motion_notify_event_on_event_box(Gtk.Widget widget, Gdk.EventMotion event)
|
2015-08-27 17:31:54 +00:00
|
|
|
{
|
2015-12-30 22:29:19 +00:00
|
|
|
update_hide_show_options(event.window, (int)event.x, (int)event.y);
|
|
|
|
return false;
|
2015-08-27 17:31:54 +00:00
|
|
|
}
|
2012-07-09 20:48:27 +00:00
|
|
|
}
|
|
|
|
|
2013-06-23 19:06:29 +00:00
|
|
|
// ex:ts=4 noet
|