gitg-diff-view-commit-details.vala 9.02 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
 * This file is part of gitg
 *
 * Copyright (C) 2015 - Jesse van den Kieboom
 *
 * 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/>.
 */

[GtkTemplate (ui = "/org/gnome/gitg/ui/gitg-diff-view-commit-details.ui")]
class Gitg.DiffViewCommitDetails : Gtk.Grid
{
	[GtkChild( name = "image_avatar" )]
24
	private unowned Gtk.Image d_image_avatar;
25
26

	[GtkChild( name = "label_author" )]
27
	private unowned Gtk.Label d_label_author;
28
29

	[GtkChild( name = "label_author_date" )]
30
	private unowned Gtk.Label d_label_author_date;
31
32

	[GtkChild( name = "label_committer" )]
33
	private unowned Gtk.Label d_label_committer;
34
35

	[GtkChild( name = "label_committer_date" )]
36
	private unowned Gtk.Label d_label_committer_date;
37

38
	[GtkChild( name = "label_subject" )]
39
	private unowned Gtk.Label d_label_subject;
40
41

	[GtkChild( name = "label_sha1" )]
42
	private unowned Gtk.Label d_label_sha1;
43
44

	[GtkChild( name = "grid_parents_container" )]
45
	private unowned Gtk.Grid d_grid_parents_container;
46
47

	[GtkChild( name = "grid_parents" )]
48
	private unowned Gtk.Grid d_grid_parents;
49
50

	[GtkChild( name = "expander_files" )]
51
	private unowned Gtk.Expander d_expander_files;
52

53
	[GtkChild( name = "label_expand_collapse_files" )]
54
	private unowned Gtk.Label d_label_expand_collapse_files;
55

56
57
58
59
60
61
62
63
64
65
66
67
	public bool expanded
	{
		get { return d_expander_files.expanded; }
		set
		{
			if (d_expander_files.expanded != value)
			{
				d_expander_files.expanded = value;
			}
		}
	}

68
69
70
	public bool expander_visible
	{
		get { return d_expander_files.visible; }
71
72
73
74
75
76

		set
		{
			d_expander_files.visible = value;
			d_label_expand_collapse_files.visible = value;
		}
77
78
	}

79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
	private Cancellable? d_avatar_cancel;

	private Ggit.Commit? d_commit;

	public Ggit.Commit? commit
	{
		get { return d_commit; }
		construct set
		{
			if (d_commit != value)
			{
				d_commit = value;
				update();
			}
		}
	}

	private Ggit.Commit d_parent_commit;

	public Ggit.Commit parent_commit
	{
		get { return d_parent_commit; }
		set
		{
			if (d_parent_commit != value)
			{
				d_parent_commit = value;

107
				if (value != null)
108
				{
109
110
111
112
113
114
					var button = d_parents_map[value.get_id()];

					if (button != null)
					{
						button.active = true;
					}
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
				}
			}
		}
	}

	private bool d_use_gravatar;

	public bool use_gravatar
	{
		get { return d_use_gravatar; }
		construct set
		{
			d_use_gravatar = value;
			update_avatar();
		}
	}

132
133
	public Gitg.Repository? repository {get; set; }

134
135
	private Gee.HashMap<Ggit.OId, Gtk.RadioButton> d_parents_map;

136
	private GLib.Regex regex_url = /\w+:(\/?\/?)[^\s]+/;
137
138
	private Ggit.Config config {get; set;}
	private GLib.Regex regex_custom_links = /gitg\.custom-link\.(.+)\.regex/;
139

140
141
142
	construct
	{
		d_expander_files.notify["expanded"].connect(() => {
143
144
			if (d_expander_files.expanded)
			{
145
				d_label_expand_collapse_files.label = _("Collapse all");
146
147
148
			}
			else
			{
149
				d_label_expand_collapse_files.label = _("Expand all");
150
151
			}

152
153
			notify_property("expanded");
		});
154
155

		use_gravatar = true;
156
157
	}

158
159
160
161
162
163
164
165
166
167
	protected override void dispose()
	{
		if (d_avatar_cancel != null)
		{
			d_avatar_cancel.cancel();
		}

		base.dispose();
	}

168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
	private string author_to_markup(Ggit.Signature author)
	{
		var name = Markup.escape_text(author.get_name());
		var email = Markup.escape_text(author.get_email());

		return "%s &lt;<a href=\"mailto:%s\">%s</a>&gt;".printf(name, email, email);
	}

	private void update()
	{
		d_parents_map = new Gee.HashMap<Ggit.OId, Gtk.RadioButton>((oid) => oid.hash(), (o1, o2) => o1.equal(o2));

		foreach (var child in d_grid_parents.get_children())
		{
			child.destroy();
		}

		if (commit == null)
		{
			return;
		}

190
		d_label_subject.set_markup(subject_to_markup(Markup.escape_text(commit.get_subject())));
191
192
193
194
195
196
197
198
199
200
201
202
203
		d_label_sha1.label = commit.get_id().to_string();

		var author = commit.get_author();

		d_label_author.label = author_to_markup(author);
		d_label_author_date.label = author.get_time().to_timezone(author.get_time_zone()).format("%x %X %z");

		var committer = commit.get_committer();

		if (committer.get_name() != author.get_name() ||
		    committer.get_email() != author.get_email() ||
		    committer.get_time().compare(author.get_time()) != 0)
		{
204
			d_label_committer.label = _("Committed by %s").printf(author_to_markup(committer));
205
206
207
208
			d_label_committer_date.label = committer.get_time().to_timezone(committer.get_time_zone()).format("%x %X %z");
		}
		else
		{
209
210
			d_label_committer.label = "";
			d_label_committer_date.label = "";
211
212
213
214
215
		}

		var parents = commit.get_parents();
		var first_parent = parents.size == 0 ? null : parents.get(0);

216
		parent_commit = first_parent;
217
218
219
220
221
222

		if (parents.size > 1)
		{
			d_grid_parents_container.show();
			var grp = new SList<Gtk.RadioButton>();

223
224
			Gtk.RadioButton? first = null;

225
226
227
228
229
230
			foreach (var parent in parents)
			{
				var pid = parent.get_id().to_string().substring(0, 6);
				var psubj = parent.get_subject();

				var button = new Gtk.RadioButton.with_label(grp, @"$pid: $psubj");
231
232
233
234
235
236
237
238

				if (first == null)
				{
					first = button;
				}

				button.group = first;

239
240
241
242
243
244
245
				d_parents_map[parent.get_id()] = button;

				button.show();
				d_grid_parents.add(button);

				var par = parent;

246
247
248
249
				button.toggled.connect(() => {
					if (button.active) {
						parent_commit = par;
					}
250
251
252
253
254
255
256
257
258
259
260
				});
			}
		}
		else
		{
			d_grid_parents_container.hide();
		}

		update_avatar();
	}

261
262
	private string subject_to_markup(string subject_text)
	{
263
		return parse_links_on_subject(subject_text);
264
265
	}

266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
	private string parse_links_on_subject(string subject_text)
	{
		string result = subject_text.dup();
		try
		{
			GLib.MatchInfo matchInfo;
			regex_url.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();
			}

281
			result = parse_smart_text(result);
282
283
284
285
286
287
288
		}
		catch(Error e)
		{
		}
		return result;
	}

289
	private string parse_smart_text(string subject_text)
290
	{
Gaurav Agrawal's avatar
Gaurav Agrawal committed
291
		string result = subject_text;
292
		if (repository != null)
293
		{
294
			result = subject_text.dup();
Gaurav Agrawal's avatar
Gaurav Agrawal committed
295
			try
296
			{
297
298
299
300
301
302
303
304
				var conf = repository.get_config().snapshot();
				conf.match_foreach(regex_custom_links, (match_info, value) => {
					string group = match_info.fetch(1);
					debug ("found custom-link group: %s", group);
					debug (value == null ? "es nulo": "es vacio");
					string custom_link_regexp = value;
					string replacement_key = "gitg.custom-link.%s.replacement".printf(group);
					try
305
					{
306
						string custom_link_replacement = conf.get_string(replacement_key);
307

308
309
310
311
						var custom_regex = new Regex (custom_link_regexp);
						try
						{
							GLib.MatchInfo matchInfo;
312

313
							custom_regex.match (subject_text, 0, out matchInfo);
314

315
316
317
318
319
320
							while (matchInfo.matches ())
							{
								string text = matchInfo.fetch(0);
								string link = text.dup();
								debug ("found: %s", link);
								if (custom_link_replacement != null)
321
								{
322
									link = custom_regex.replace(link, text.length, 0, custom_link_replacement);
323
								}
324
325
326
								result = result.replace(text, "<a href=\"%s\" title=\"%s\">%s</a>".printf(link, link, text));

								matchInfo.next();
Gaurav Agrawal's avatar
Gaurav Agrawal committed
327
							}
328
						}
329
330
331
332
333
334
						catch(Error e)
						{
						}
					} catch (Error e)
					{
						warning ("Cannot read git config: %s", e.message);
335
					}
336
337
338
339
					return 0;
				});
			}
			catch(Error e)
Gaurav Agrawal's avatar
Gaurav Agrawal committed
340
			{
341
				warning ("Cannot read git config: %s", e.message);
342
343
344
345
346
			}
		}
		return result;
	}

347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
	private void update_avatar()
	{
		if (commit == null)
		{
			return;
		}

		if (d_use_gravatar)
		{
			if (d_avatar_cancel != null)
			{
				d_avatar_cancel.cancel();
			}

			d_avatar_cancel = new Cancellable();
			var cancel = d_avatar_cancel;

			var cache = AvatarCache.default();

			cache.load.begin(commit.get_author().get_email(), d_image_avatar.pixel_size, cancel, (obj, res) => {
				if (!cancel.is_cancelled())
				{
					var pixbuf = cache.load.end(res);

					if (pixbuf != null)
					{
						d_image_avatar.pixbuf = pixbuf;
374
						d_image_avatar.get_style_context().remove_class("dim-label");
375
376
377
378
					}
					else
					{
						d_image_avatar.icon_name = "avatar-default-symbolic";
379
						d_image_avatar.get_style_context().add_class("dim-label");
380
381
382
383
384
385
386
387
388
389
390
391
					}
				}

				if (cancel == d_avatar_cancel)
				{
					d_avatar_cancel = null;
				}
			});
		}
		else
		{
			d_image_avatar.icon_name = "avatar-default-symbolic";
392
			d_image_avatar.get_style_context().add_class("dim-label");
393
394
		}
	}
395
396
397
398
399
400
401
402
403
404
405
406

	[GtkCallback]
	private bool button_press_on_event_box_expand_collapse(Gdk.EventButton event)
	{
		if (event.button == Gdk.BUTTON_PRIMARY)
		{
			d_expander_files.expanded = !d_expander_files.expanded;
			return true;
		}

		return false;
	}
407
408
409
}

// ex:ts=4 noet