1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3  * git-shell-test
4  * Copyright (C) James Liggett 2009 <jrliggett@cox.net>
5  *
6  * git-shell-test 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  * git-shell-test 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-command-bar.h"
21 
22 /* Reasonable default */
23 #define DEFAULT_MAX_TEXT_WIDTH 25
24 
25 /**
26  * SECTION: anjuta-command-bar
27  * @short_description: Widget that lays out commands in a vertical row of
28  *					   buttons and frames.
29  * @see_also: #AnjutaDock, #GtkAction
30  * @include: libanjuta/anjuta-command-bar.h
31  *
32  * AnjutaCommandBar provides a convenient way to arrange several sets of
33  * commands into one widget. It separates commands into different groups of
34  * actions, with only one group visible at a time.
35  */
36 
37 G_DEFINE_TYPE (AnjutaCommandBar, anjuta_command_bar, GTK_TYPE_NOTEBOOK);
38 
39 struct _AnjutaCommandBarPriv
40 {
41 	GHashTable *action_groups;
42 	GHashTable *widgets;
43 
44 	gint max_text_width;
45 };
46 
47 enum
48 {
49 	PROP_0,
50 	PROP_MAX_TEXT_WIDTH,
51 	PROP_LAST
52 };
53 
54 static void
anjuta_command_bar_init(AnjutaCommandBar * self)55 anjuta_command_bar_init (AnjutaCommandBar *self)
56 {
57 	self->priv = g_new0 (AnjutaCommandBarPriv, 1);
58 
59 	gtk_notebook_set_show_border (GTK_NOTEBOOK (self), FALSE);
60 	gtk_notebook_set_show_tabs (GTK_NOTEBOOK (self), FALSE);
61 
62 	/* The action groups table contains the GtkActionGroup objects that
63 	 * correspond to each page of the action bar. The widgets table contain's
64 	 * each group's set of buttons and frames. */
65 	self->priv->action_groups = g_hash_table_new_full (g_str_hash, g_str_equal,
66 	                                                   NULL, g_object_unref);
67 	self->priv->widgets = g_hash_table_new (g_str_hash, g_str_equal);
68 }
69 
70 static void
anjuta_command_bar_finalize(GObject * object)71 anjuta_command_bar_finalize (GObject *object)
72 {
73 	AnjutaCommandBar *self;
74 
75 	self = ANJUTA_COMMAND_BAR (object);
76 
77 	g_hash_table_destroy (self->priv->action_groups);
78 	g_hash_table_destroy (self->priv->widgets);
79 
80 	G_OBJECT_CLASS (anjuta_command_bar_parent_class)->finalize (object);
81 }
82 
83 static void
anjuta_command_bar_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)84 anjuta_command_bar_get_property (GObject* object, guint prop_id, GValue* value,
85                                  GParamSpec* pspec)
86 {
87     AnjutaCommandBar* self = ANJUTA_COMMAND_BAR (object);
88 
89     switch (prop_id)
90     {
91         case PROP_MAX_TEXT_WIDTH:
92             g_value_set_int (value,
93                              self->priv->max_text_width);
94             break;
95 
96         default:
97             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
98     }
99 }
100 
101 static void
anjuta_command_bar_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)102 anjuta_command_bar_set_property (GObject* object, guint prop_id,
103                                 const GValue* value, GParamSpec* pspec)
104 {
105     AnjutaCommandBar* self = ANJUTA_COMMAND_BAR (object);
106 
107     switch (prop_id)
108     {
109         case PROP_MAX_TEXT_WIDTH:
110             self->priv->max_text_width = g_value_get_int (value);
111             break;
112 
113         default:
114             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
115     }
116 }
117 
118 static void
anjuta_command_bar_class_init(AnjutaCommandBarClass * klass)119 anjuta_command_bar_class_init (AnjutaCommandBarClass *klass)
120 {
121 	GObjectClass* object_class = G_OBJECT_CLASS (klass);
122 
123 	object_class->finalize = anjuta_command_bar_finalize;
124 	object_class->set_property = anjuta_command_bar_set_property;
125 	object_class->get_property = anjuta_command_bar_get_property;
126 
127 	g_object_class_install_property (object_class,
128 	                                 PROP_MAX_TEXT_WIDTH,
129 	                                 g_param_spec_int ("max-text-width",
130 	                                                   "",
131 	                                                   "",
132 	                                                   10,
133 	                                                   1000,
134 	                                                   DEFAULT_MAX_TEXT_WIDTH,
135 	                                                   G_PARAM_WRITABLE|G_PARAM_READABLE|G_PARAM_CONSTRUCT_ONLY));
136 }
137 
138 /**
139  * anjuta_command_bar_new:
140  *
141  * Creates a new AnjutaCommandBar.
142  * Returns: A new AnjutaCommandBar
143  */
144 GtkWidget *
anjuta_command_bar_new(void)145 anjuta_command_bar_new (void)
146 {
147 	return g_object_new (ANJUTA_TYPE_COMMAND_BAR, NULL);
148 }
149 
150 /**
151  * anjuta_command_bar_add_action_group:
152  * @self: An AnjutaCommandBar
153  * @group_name: A unique name for this group of entries
154  * @entries: (array length=num_entries): A list of entries to add
155  * @num_entries: The number of items pointed to by entries
156  * @user_data: User data to pass to the entry callback
157  *
158  * Adds a group of entries to an AnjutaCommandBar.
159  */
160 void
anjuta_command_bar_add_action_group(AnjutaCommandBar * self,const gchar * group_name,const AnjutaCommandBarEntry * entries,int num_entries,gpointer user_data)161 anjuta_command_bar_add_action_group (AnjutaCommandBar *self,
162                                      const gchar *group_name,
163                                      const AnjutaCommandBarEntry *entries,
164                                      int num_entries, gpointer user_data)
165 {
166 	GtkWidget *vbox;
167 	GtkWidget *scrolled_window;
168 	GtkWidget *current_vbox;
169 	GtkActionGroup *action_group;
170 	int i;
171 
172 	vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
173 	scrolled_window = gtk_scrolled_window_new (NULL, NULL);
174 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
175 	                                GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
176 
177 	g_hash_table_insert (self->priv->widgets, (gchar *) group_name,
178 	                     scrolled_window);
179 
180 	action_group = gtk_action_group_new (group_name);
181 
182 	g_hash_table_insert (self->priv->action_groups, (gchar *) group_name,
183 	                     action_group);
184 
185 	/* The current_vbox is the vbox we're currently adding buttons to. As
186 	 * frame entries are encountered, the current box changes to the newly
187 	 * created frame vbox. But start by adding any other buttons to the top
188 	 * level vbox. */
189 	current_vbox = vbox;
190 
191 	for (i = 0; i < num_entries; i++)
192 	{
193 		if (entries[i].type == ANJUTA_COMMAND_BAR_ENTRY_BUTTON)
194 		{
195 			GtkAction *action;
196 			GtkWidget *button;
197 			GtkWidget *button_label;
198 
199 			action = gtk_action_new (entries[i].action_name, _(entries[i].label),
200 			                         _(entries[i].tooltip), entries[i].stock_icon);
201 			button = gtk_button_new_with_label (_(entries[i].label));
202 
203 
204 			gtk_action_group_add_action (action_group, action);
205 
206 			gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
207 			button_label = gtk_bin_get_child (GTK_BIN (button));
208 			gtk_label_set_max_width_chars (GTK_LABEL (button_label), self->priv->max_text_width);
209 			gtk_label_set_ellipsize (GTK_LABEL (button_label), PANGO_ELLIPSIZE_END);
210 
211 			/* Left-align button contents */
212 			gtk_misc_set_alignment (GTK_MISC (button_label), 0.0, 0.5);
213 			g_object_set (G_OBJECT (button), "xalign", 0.0, NULL);
214 
215 			if (entries[i].stock_icon)
216 			{
217 				GtkWidget *button_image;
218 
219 				button_image = gtk_action_create_icon (action,
220 				                                       GTK_ICON_SIZE_BUTTON);
221 				gtk_button_set_image (GTK_BUTTON (button), button_image);
222 			}
223 
224 			gtk_activatable_set_related_action (GTK_ACTIVATABLE (button),
225 			                                    action);
226 			gtk_widget_show_all (button);
227 
228 
229 			g_signal_connect (G_OBJECT (action), "activate",
230 			                  entries[i].callback,
231 			                  user_data);
232 
233 
234 			gtk_box_pack_start (GTK_BOX (current_vbox), button, FALSE, FALSE,
235 			                    2);
236 		}
237 		else
238 		{
239 			gchar *frame_label_text;
240 			GtkWidget *frame_label;
241 			GtkWidget *frame;
242 			GtkWidget *frame_vbox;
243 
244 			frame_label_text = g_strdup_printf ("<b>%s</b>", _(entries[i].label));
245 			frame_label = gtk_label_new (NULL);
246 			frame = gtk_frame_new (NULL);
247 
248 			gtk_label_set_markup(GTK_LABEL (frame_label), frame_label_text);
249 			gtk_frame_set_label_widget (GTK_FRAME (frame), frame_label);
250 
251 			g_free (frame_label_text);
252 
253 			frame_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
254 
255 			g_object_set (G_OBJECT (frame), "shadow-type", GTK_SHADOW_NONE,
256 			              NULL);
257 
258 			gtk_container_add (GTK_CONTAINER (frame), frame_vbox);
259 			gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 2);
260 
261 			current_vbox = frame_vbox;
262 		}
263 	}
264 
265 	gtk_container_add (GTK_CONTAINER (scrolled_window),
266 	                   vbox);
267 	gtk_widget_show_all (scrolled_window);
268 	gtk_notebook_append_page (GTK_NOTEBOOK (self), scrolled_window, NULL);
269 }
270 
271 /**
272  * anjuta_command_bar_remove_action_group:
273  * @self: An AnjutaCommandBar
274  * @group_name: Name of the action group to remove
275  *
276  * Removes an action group from an AnjutaCommandBar.
277  */
278 void
anjuta_command_bar_remove_action_group(AnjutaCommandBar * self,const gchar * group_name)279 anjuta_command_bar_remove_action_group (AnjutaCommandBar *self,
280                                         const gchar *group_name)
281 {
282 	GtkWidget *page_widget;
283 	int page_num;
284 
285 	page_widget = g_hash_table_lookup (self->priv->action_groups, group_name);
286 
287 	if (page_widget)
288 	{
289 		page_num = gtk_notebook_page_num (GTK_NOTEBOOK (self), page_widget);
290 
291 		gtk_notebook_remove_page (GTK_NOTEBOOK (self), page_num);
292 
293 		g_hash_table_remove (self->priv->action_groups, group_name);
294 		g_hash_table_remove (self->priv->widgets, group_name);
295 	}
296 	else
297 		g_warning ("Action group %s not found.", group_name);
298 
299 }
300 
301 /**
302  * anjuta_command_bar_show_action_group:
303  * @self: An AnjutaCommandBar
304  * @group_name: The name of the action group to show
305  *
306  * Causes the actions in the given group to become visible, replacing the
307  * previously visible group.
308  */
309 void
anjuta_command_bar_show_action_group(AnjutaCommandBar * self,const gchar * group_name)310 anjuta_command_bar_show_action_group (AnjutaCommandBar *self,
311                                       const gchar *group_name)
312 {
313 	GtkWidget *page_widget;
314 	int page_num;
315 
316 	page_widget = g_hash_table_lookup (self->priv->widgets, group_name);
317 
318 	if (page_widget)
319 	{
320 		page_num = gtk_notebook_page_num (GTK_NOTEBOOK (self), page_widget);
321 
322 		gtk_notebook_set_current_page (GTK_NOTEBOOK (self), page_num);
323 	}
324 	else
325 		g_warning ("Action group %s not found.", group_name);
326 
327 }
328 
329 /**
330  * anjuta_command_bar_get_action_group:
331  * @self An AnjutaCommandBar
332  * @group_name: The name of the action group
333  *
334  * Returns: The #GtkActionGroup with the given @group_name
335  */
336 GtkActionGroup *
anjuta_command_bar_get_action_group(AnjutaCommandBar * self,const gchar * group_name)337 anjuta_command_bar_get_action_group (AnjutaCommandBar *self,
338                                      const gchar *group_name)
339 {
340 	GtkActionGroup *action_group;
341 
342 	action_group = g_hash_table_lookup (self->priv->action_groups, group_name);
343 
344 	if (!action_group)
345 		g_warning ("Action group %s not found.", group_name);
346 
347 	return action_group;
348 }
349 
350 /**
351  * anjuta_command_bar_get_action:
352  * @self: An AnjutaCommandBar
353  * @group_name: The name of the #GtkActionGroup to look for the action in
354  * @action_name: The name of the action
355  *
356  * Retrieves a #GtkAction object in the given group with the given name
357  */
358 GtkAction *
anjuta_command_bar_get_action(AnjutaCommandBar * self,const gchar * group_name,const gchar * action_name)359 anjuta_command_bar_get_action (AnjutaCommandBar *self, const gchar *group_name,
360                                const gchar *action_name)
361 {
362 	GtkActionGroup *action_group;
363 	GtkAction *action;
364 
365 	action = NULL;
366 
367 	action_group = anjuta_command_bar_get_action_group (self, group_name);
368 
369 	if (action_group)
370 		action = gtk_action_group_get_action (action_group, action_name);
371 
372 	return action;
373 }
374