[gitg/wip/gaurav/clickable-links-subject-textview: 13/15] Change subject from label to textview
- From: Alberto Fanjul <albfan src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gitg/wip/gaurav/clickable-links-subject-textview: 13/15] Change subject from label to textview
- Date: Fri, 12 Apr 2019 11:18:06 +0000 (UTC)
commit c7b48f39a2f29c5cd7a2fddfdc38d1e9645eb08b
Author: Alberto Fanjul <albertofanjul gmail com>
Date: Mon Jan 21 11:26:54 2019 +0100
Change subject from label to textview
libgitg/gitg-diff-view-commit-details.vala | 324 +++++++++++++++++----
libgitg/gitg-diff-view.vala | 8 +-
.../resources/ui/gitg-diff-view-commit-details.ui | 43 +--
libgitg/resources/ui/libgitg-style.css | 5 +
4 files changed, 294 insertions(+), 86 deletions(-)
---
diff --git a/libgitg/gitg-diff-view-commit-details.vala b/libgitg/gitg-diff-view-commit-details.vala
index 26f4d464..d87a2358 100644
--- a/libgitg/gitg-diff-view-commit-details.vala
+++ b/libgitg/gitg-diff-view-commit-details.vala
@@ -35,8 +35,8 @@ class Gitg.DiffViewCommitDetails : Gtk.Grid
[GtkChild( name = "label_committer_date" )]
private Gtk.Label d_label_committer_date;
- [GtkChild( name = "label_subject" )]
- private Gtk.Label d_label_subject;
+ [GtkChild( name = "textview_subject" )]
+ private Gtk.TextView d_label_subject;
[GtkChild( name = "label_sha1" )]
private Gtk.Label d_label_sha1;
@@ -53,6 +53,13 @@ class Gitg.DiffViewCommitDetails : Gtk.Grid
[GtkChild( name = "label_expand_collapse_files" )]
private Gtk.Label d_label_expand_collapse_files;
+ private Gdk.RGBA d_color_link;
+ private Gdk.RGBA color_hovered_link;
+ private bool hovering_over_link = false;
+ private Gtk.TextTag hover_tag = null;
+ public Repository repository { get; set; }
+ public bool new_is_workdir { get; set; }
+
public bool expanded
{
get { return d_expander_files.expanded; }
@@ -122,6 +129,246 @@ class Gitg.DiffViewCommitDetails : Gtk.Grid
Object(commit: commit);
}
+ protected override void constructed()
+ {
+ d_label_subject.event_after.connect (on_event_after);
+ d_label_subject.key_press_event.connect (on_key_press);
+ d_label_subject.motion_notify_event.connect (on_motion_notify_event);
+ d_label_subject.has_tooltip = true;
+ d_label_subject.query_tooltip.connect (on_query_tooltip_event);
+ d_label_subject.style_updated.connect (load_colors_from_theme);
+ load_colors_from_theme(d_label_subject);
+ }
+
+ private bool on_query_tooltip_event(int x, int y, bool keyboard_tooltip, Gtk.Tooltip tooltip)
+ {
+ Gtk.TextIter iter;
+
+ if (d_label_subject.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)
+ {
+ message("Cannot open "+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.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.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;
+ }
+
+ public void restore_tag_color_link (Gtk.TextTag tag)
+ {
+ Gdk.RGBA? color = tag.get_data<Gdk.RGBA?>("color_link");
+ tag.foreground_rgba = color;
+ }
+
private bool d_use_gravatar;
public bool use_gravatar
@@ -185,8 +432,12 @@ class Gitg.DiffViewCommitDetails : Gtk.Grid
{
return;
}
+ d_label_subject.buffer.set_text(commit.get_subject());
+ var buffer = d_label_subject.get_buffer();
+ apply_link_tags(buffer, /\w+:(\/?\/?)[^\s]+/, null, d_color_link, false, false);
- d_label_subject.label = parse_links_on_subject(commit.get_subject());
+ var ini_file = "%s/.git/config".printf(repository.get_workdir().get_path());
+ read_ini_file(buffer, ini_file);
d_label_sha1.label = commit.get_id().to_string();
var author = commit.get_author();
@@ -257,34 +508,8 @@ class Gitg.DiffViewCommitDetails : Gtk.Grid
update_avatar();
}
- private string parse_links_on_subject(string subject_text)
+ private void read_ini_file(Gtk.TextBuffer buffer, string config_file)
{
- string result = subject_text.dup();
- try
- {
- GLib.MatchInfo matchInfo;
- GLib.Regex regex = /\w+:(\/?\/?)[^\s]+/;
- regex.match (subject_text, 0, out matchInfo);
-
- while (matchInfo.matches ())
- {
- string text = matchInfo.fetch(0);
- result = result.replace(text, "<a href=\"%s\">%s</a>".printf(text, text));
- matchInfo.next();
- }
-
- result = parse_ini_file(result, ".git/config");
- }
- catch(Error e)
- {
- }
- return result;
- }
-
- //TODO: pass repository
- private string parse_ini_file(string subject_text, string config_file)
- {
- string result = subject_text.dup();
GLib.KeyFile file = new GLib.KeyFile();
try
@@ -297,51 +522,22 @@ class Gitg.DiffViewCommitDetails : Gtk.Grid
{
string custom_link_regexp = file.get_string (group, "regexp");
string custom_link_replacement = file.get_string (group,
"replacement");
- message("found group: %s", custom_link_regexp);
bool custom_color = file.has_key (group, "color");
- string color = null;
+ Gdk.RGBA color = d_color_link;
if (custom_color)
{
string custom_link_color = file.get_string (group,
"color");
- color = custom_link_color;
- }
- //TODO: Extract to replace function
- var regex = new Regex (custom_link_regexp);
- try
- {
- GLib.MatchInfo matchInfo;
-
- regex.match (subject_text, 0, out matchInfo);
-
- while (matchInfo.matches ())
- {
- string text = matchInfo.fetch(0);
- string link = text.dup();
- message("found: %s", link);
- if (custom_link_replacement != null)
- {
- link = regex.replace(link,
text.length, 0, custom_link_replacement);
- }
- //if (color != null) {
- // result = result.replace(text, "<a
href=\"%s\" title=\"%s\" style=\"color:%s\">%s</a>".printf(link, link, color, text));
- //} else {
- result = result.replace(text, "<a
href=\"%s\" title=\"%s\">%s</a>".printf(link, link, text));
- //}
-
- matchInfo.next();
- }
- }
- catch(Error e)
- {
+ color = Gdk.RGBA();
+ color.parse(custom_link_color);
}
+ apply_link_tags(buffer, new Regex (custom_link_regexp),
custom_link_replacement, color, custom_color, true);
}
}
}
} catch (Error e)
{
- message("Cannot read %s %s", config_file, e.message);
+ message("Cannot read %s: %s", config_file, e.message);
}
- return result;
}
private void update_avatar()
diff --git a/libgitg/gitg-diff-view.vala b/libgitg/gitg-diff-view.vala
index 3ba65403..b069dd71 100644
--- a/libgitg/gitg-diff-view.vala
+++ b/libgitg/gitg-diff-view.vala
@@ -49,10 +49,10 @@ public class Gitg.DiffView : Gtk.Grid
private ulong d_parent_commit_notify;
private bool d_changes_inline;
- Gdk.RGBA d_color_link;
- Gdk.RGBA color_hovered_link;
- bool hovering_over_link = false;
- Gtk.TextTag hover_tag = null;
+ private Gdk.RGBA d_color_link;
+ private Gdk.RGBA color_hovered_link;
+ private bool hovering_over_link = false;
+ private Gtk.TextTag hover_tag = null;
private uint d_reveal_options_timeout;
private uint d_unreveal_options_timeout;
diff --git a/libgitg/resources/ui/gitg-diff-view-commit-details.ui
b/libgitg/resources/ui/gitg-diff-view-commit-details.ui
index dee13bea..25a1e2db 100644
--- a/libgitg/resources/ui/gitg-diff-view-commit-details.ui
+++ b/libgitg/resources/ui/gitg-diff-view-commit-details.ui
@@ -120,24 +120,6 @@
<property name="top_attach">0</property>
</packing>
</child>
- <child>
- <object class="GtkLabel" id="label_subject">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="halign">start</property>
- <property name="valign">start</property>
- <property name="label">Message</property>
- <property name="wrap">True</property>
- <property name="selectable">True</property>
- <property name="ellipsize">end</property>
- <property name="use_markup">True</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">1</property>
- <property name="width">2</property>
- </packing>
- </child>
<child>
<object class="GtkGrid" id="grid_parents_container">
<property name="visible">True</property>
@@ -180,7 +162,28 @@
<property name="width">2</property>
</packing>
</child>
+ <child>
+ <object class="GtkTextView" id="textview_subject">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="editable">False</property>
+ <property name="cursor_visible">False</property>
+ <style>
+ <class name="commit-subject"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
</object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
</child>
<child>
<object class="GtkGrid" id="grid_bottom">
@@ -199,6 +202,10 @@
<class name="dim-label"/>
</style>
</object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
</child>
<child>
<object class="GtkEventBox" id="event_box_expand_collapse_files">
diff --git a/libgitg/resources/ui/libgitg-style.css b/libgitg/resources/ui/libgitg-style.css
index d9d27594..e0371d7f 100644
--- a/libgitg/resources/ui/libgitg-style.css
+++ b/libgitg/resources/ui/libgitg-style.css
@@ -37,6 +37,11 @@ textview.commit-message text {
color: @theme_text_color;
}
+textview.commit-subject text{
+ background-color: @theme_bg_color;
+ color: @theme_text_color;
+}
+
gitg-diffstat {
border: 1px inset shade(@borders, 1.2);
border-radius: 5px;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]