1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * anjuta-cell-renderer-diff.c
4 * Copyright (C) 2013 James Liggett <jrliggett@cox.net>
5 *
6 * anjuta is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * anjuta is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "anjuta-cell-renderer-diff.h"
21
22 struct _AnjutaCellRendererDiffPrivate
23 {
24 GtkCellRenderer *text_cell;
25 };
26
27
28 enum
29 {
30 PROP_0,
31
32 PROP_DIFF
33 };
34
35
36 /* Line types */
37 typedef enum
38 {
39 LINE_TYPE_HEADER,
40 LINE_TYPE_HUNK_HEADER,
41 LINE_TYPE_ADD,
42 LINE_TYPE_DELETE,
43 LINE_TYPE_CONTEXT
44 } LineType;
45
46 G_DEFINE_TYPE (AnjutaCellRendererDiff, anjuta_cell_renderer_diff, GTK_TYPE_CELL_RENDERER);
47
48 static void
anjuta_cell_renderer_diff_init(AnjutaCellRendererDiff * self)49 anjuta_cell_renderer_diff_init (AnjutaCellRendererDiff *self)
50 {
51 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, ANJUTA_TYPE_CELL_RENDERER_DIFF,
52 AnjutaCellRendererDiffPrivate);
53
54 self->priv->text_cell = gtk_cell_renderer_text_new ();
55 }
56
57 static void
anjuta_cell_renderer_diff_finalize(GObject * object)58 anjuta_cell_renderer_diff_finalize (GObject *object)
59 {
60 AnjutaCellRendererDiff *self;
61
62 self = ANJUTA_CELL_RENDERER_DIFF (object);
63
64 g_object_unref (self->priv->text_cell);
65
66 G_OBJECT_CLASS (anjuta_cell_renderer_diff_parent_class)->finalize (object);
67 }
68
69 static void
anjuta_cell_renderer_diff_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)70 anjuta_cell_renderer_diff_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
71 {
72 g_return_if_fail (ANJUTA_IS_CELL_RENDERER_DIFF (object));
73
74 switch (prop_id)
75 {
76 case PROP_DIFF:
77 anjuta_cell_renderer_diff_set_diff (ANJUTA_CELL_RENDERER_DIFF (object),
78 g_value_get_string (value));
79 break;
80 default:
81 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
82 break;
83 }
84 }
85
86 static void
anjuta_cell_renderer_diff_render(GtkCellRenderer * cell,cairo_t * cr,GtkWidget * widget,const GdkRectangle * background_area,const GdkRectangle * cell_area,GtkCellRendererState flags)87 anjuta_cell_renderer_diff_render (GtkCellRenderer *cell,
88 cairo_t *cr,
89 GtkWidget *widget,
90 const GdkRectangle *background_area,
91 const GdkRectangle *cell_area,
92 GtkCellRendererState flags)
93 {
94 AnjutaCellRendererDiff *self;
95
96 self = ANJUTA_CELL_RENDERER_DIFF (cell);
97
98 gtk_cell_renderer_render (self->priv->text_cell, cr, widget,
99 background_area, cell_area, flags);
100 }
101
102 static void
anjuta_cell_renderer_diff_get_preferred_width(GtkCellRenderer * cell,GtkWidget * widget,gint * minimum,gint * natural)103 anjuta_cell_renderer_diff_get_preferred_width (GtkCellRenderer *cell,
104 GtkWidget *widget,
105 gint *minimum,
106 gint *natural)
107 {
108 AnjutaCellRendererDiff *self;
109
110 self = ANJUTA_CELL_RENDERER_DIFF (cell);
111
112 gtk_cell_renderer_get_preferred_width (self->priv->text_cell, widget,
113 minimum, natural);
114 }
115
116 static void
anjuta_cell_renderer_diff_get_preferred_height(GtkCellRenderer * cell,GtkWidget * widget,gint * minimum,gint * natural)117 anjuta_cell_renderer_diff_get_preferred_height (GtkCellRenderer *cell,
118 GtkWidget *widget,
119 gint *minimum,
120 gint *natural)
121 {
122 AnjutaCellRendererDiff *self;
123
124 self = ANJUTA_CELL_RENDERER_DIFF (cell);
125
126 gtk_cell_renderer_get_preferred_height (self->priv->text_cell, widget,
127 minimum, natural);
128 }
129
130 static void
anjuta_cell_renderer_diff_class_init(AnjutaCellRendererDiffClass * klass)131 anjuta_cell_renderer_diff_class_init (AnjutaCellRendererDiffClass *klass)
132 {
133 GObjectClass *object_class = G_OBJECT_CLASS (klass);
134 GtkCellRendererClass *parent_class = GTK_CELL_RENDERER_CLASS (klass);
135
136 g_type_class_add_private (klass, sizeof (AnjutaCellRendererDiffPrivate));
137
138 object_class->finalize = anjuta_cell_renderer_diff_finalize;
139 object_class->set_property = anjuta_cell_renderer_diff_set_property;
140 parent_class->render = anjuta_cell_renderer_diff_render;
141 parent_class->get_preferred_width = anjuta_cell_renderer_diff_get_preferred_width;;
142 parent_class->get_preferred_height = anjuta_cell_renderer_diff_get_preferred_height;
143
144 g_object_class_install_property (object_class,
145 PROP_DIFF,
146 g_param_spec_string ("diff",
147 "diff",
148 "Diff to render",
149 "",
150 G_PARAM_WRITABLE));
151 }
152
153
154 static PangoAttrList *
create_attribute_list(const gchar * diff)155 create_attribute_list (const gchar *diff)
156 {
157 PangoAttrList *list;
158 LineType type;
159
160 list = pango_attr_list_new ();
161
162 /* Make all of the text monospace */
163 pango_attr_list_insert (list, pango_attr_family_new ("Monospace"));
164
165 /* Assume that diff points to one line of a unified diff */
166 type = LINE_TYPE_CONTEXT;
167
168 if (diff && diff[0])
169 {
170 if (*diff != ' ')
171 {
172 if (diff[0] == '@' && diff[1] == '@')
173 type = LINE_TYPE_HUNK_HEADER;
174 else if (diff[0] == '+')
175 {
176 if (g_str_has_prefix (diff, "+++ "))
177 type = LINE_TYPE_HEADER;
178 else
179 type = LINE_TYPE_ADD;
180 }
181 else if (diff[0] == '-')
182 {
183 if (g_str_has_prefix (diff, "--- "))
184 type = LINE_TYPE_HEADER;
185 else
186 type = LINE_TYPE_DELETE;
187 }
188 else
189 type = LINE_TYPE_HEADER;
190 }
191 }
192
193 switch (type)
194 {
195 case LINE_TYPE_HEADER:
196 /* Make file headers easier to see by making them bold */
197 pango_attr_list_insert (list,
198 pango_attr_weight_new (PANGO_WEIGHT_BOLD));
199 break;
200 case LINE_TYPE_HUNK_HEADER:
201 /* Dark blue */
202 pango_attr_list_insert (list,
203 pango_attr_foreground_new (0, 0, 0x8000));
204 break;
205 case LINE_TYPE_ADD:
206 /* Dark green */
207 pango_attr_list_insert (list,
208 pango_attr_foreground_new (0, 0x8000, 0));
209 break;
210 case LINE_TYPE_DELETE:
211 /* Red */
212 pango_attr_list_insert (list,
213 pango_attr_foreground_new (0xffff, 0, 0));
214 break;
215 default:
216 break;
217 };
218
219 return list;
220 }
221
222 void
anjuta_cell_renderer_diff_set_diff(AnjutaCellRendererDiff * self,const gchar * diff)223 anjuta_cell_renderer_diff_set_diff (AnjutaCellRendererDiff *self,
224 const gchar *diff)
225 {
226 PangoAttrList *attributes = NULL;
227 gchar *newline;
228 gchar *diff_without_newline = NULL;
229
230 if (diff)
231 {
232 newline = strchr (diff, '\n');
233
234 if (newline)
235 {
236 diff_without_newline = g_strndup (diff, newline - diff);
237 g_object_set (G_OBJECT (self->priv->text_cell),
238 "text", diff_without_newline,
239 NULL);
240 g_free (diff_without_newline);
241 }
242 else
243 {
244 g_object_set (G_OBJECT (self->priv->text_cell),
245 "text", diff,
246 NULL);
247 }
248
249 attributes = create_attribute_list (diff);
250
251 g_object_set (G_OBJECT (self->priv->text_cell),
252 "attributes", attributes,
253 NULL);
254
255 pango_attr_list_unref (attributes);
256 }
257 else
258 {
259 g_object_set (G_OBJECT (self->priv->text_cell),
260 "text", "", NULL);
261 }
262 }
263
264 GtkCellRenderer *
anjuta_cell_renderer_diff_new(void)265 anjuta_cell_renderer_diff_new (void)
266 {
267 return g_object_new (ANJUTA_TYPE_CELL_RENDERER_DIFF, NULL);
268 }
269
270