1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 
3 /*
4  *  GThumb
5  *
6  *  Copyright (C) 2009 Free Software Foundation, Inc.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <config.h>
23 #include <gtk/gtk.h>
24 #include "glib-utils.h"
25 #include "gth-main.h"
26 #include "gth-property-view.h"
27 #include "gth-sidebar.h"
28 #include "gth-sidebar-section.h"
29 #include "gth-toolbox.h"
30 #include "gtk-utils.h"
31 
32 
33 #define GTH_SIDEBAR_PAGE_PROPERTIES "GthSidebar.Properties"
34 #define GTH_SIDEBAR_PAGE_TOOLS "GthSidebar.Tools"
35 #define GTH_SIDEBAR_PAGE_EMPTY "GthSidebar.Empty"
36 #define MIN_SIDEBAR_WIDTH 365
37 
38 
39 struct _GthSidebarPrivate {
40 	GtkWidget   *properties;
41 	GtkWidget   *toolbox;
42 	GthFileData *file_data;
43 	const char  *selected_page;
44 	GList       *sections;
45 	int          n_visibles;
46 };
47 
48 
G_DEFINE_TYPE_WITH_CODE(GthSidebar,gth_sidebar,GTK_TYPE_STACK,G_ADD_PRIVATE (GthSidebar))49 G_DEFINE_TYPE_WITH_CODE (GthSidebar,
50 			 gth_sidebar,
51 			 GTK_TYPE_STACK,
52 			 G_ADD_PRIVATE (GthSidebar))
53 
54 
55 static void
56 gth_sidebar_finalize (GObject *object)
57 {
58 	GthSidebar *sidebar = GTH_SIDEBAR (object);
59 
60 	_g_object_unref (sidebar->priv->file_data);
61 
62 	G_OBJECT_CLASS (gth_sidebar_parent_class)->finalize (object);
63 }
64 
65 
66 static void
gth_sidebar_class_init(GthSidebarClass * klass)67 gth_sidebar_class_init (GthSidebarClass *klass)
68 {
69 	GObjectClass *object_class;
70 
71 	object_class = (GObjectClass *) klass;
72 	object_class->finalize = gth_sidebar_finalize;
73 }
74 
75 
76 static void
gth_sidebar_init(GthSidebar * sidebar)77 gth_sidebar_init (GthSidebar *sidebar)
78 {
79 	sidebar->priv = gth_sidebar_get_instance_private (sidebar);
80 	sidebar->priv->file_data = NULL;
81 	sidebar->priv->sections = NULL;
82 	sidebar->priv->selected_page = GTH_SIDEBAR_PAGE_EMPTY;
83 	sidebar->priv->n_visibles = 0;
84 }
85 
86 
87 #define STATUS_DELIMITER ":"
88 #define STATUS_EXPANDED  "expanded"
89 #define STATUS_NOT_EXPANDED  "collapsed"
90 
91 
92 typedef struct {
93 	char     *id;
94 	gboolean  expanded;
95 } SectionStatus;
96 
97 
98 static SectionStatus *
section_status_new(const char * str)99 section_status_new (const char *str)
100 {
101 	SectionStatus  *status;
102 	char          **strv;
103 
104 	status = g_new (SectionStatus, 1);
105 	status->id = NULL;
106 	status->expanded = TRUE;
107 
108 	strv = g_strsplit (str, STATUS_DELIMITER, 2);
109 	if (strv[0] != NULL)
110 		status->id = g_strdup (strv[0]);
111 	if (strv[1] != NULL)
112 		status->expanded = (strcmp (strv[1], STATUS_EXPANDED) == 0);
113 	g_strfreev (strv);
114 
115 	return status;
116 }
117 
118 
119 static void
section_status_free(SectionStatus * status)120 section_status_free (SectionStatus *status)
121 {
122 	g_free (status->id);
123 	g_free (status);
124 }
125 
126 
127 static GHashTable *
create_section_status_hash(char ** sections_status)128 create_section_status_hash (char **sections_status)
129 {
130 	GHashTable *status_hash;
131 	int         i;
132 
133 	status_hash = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) section_status_free);
134 	if (sections_status == NULL)
135 		return status_hash;
136 
137 	for (i = 0; sections_status[i] != NULL; i++) {
138 		SectionStatus *status = section_status_new (sections_status[i]);
139 		if (status != NULL)
140 			g_hash_table_insert (status_hash, status->id, status);
141 	}
142 
143 	return status_hash;
144 }
145 
146 
147 static void
_gth_sidebar_add_sections(GthSidebar * sidebar,char ** sections_status)148 _gth_sidebar_add_sections (GthSidebar  *sidebar,
149 			   char       **sections_status)
150 {
151 	GArray     *children;
152 	GHashTable *status_hash;
153 	int         i;
154 
155 	children = gth_main_get_type_set ("file-properties");
156 	if (children == NULL)
157 		return;
158 
159 	status_hash = create_section_status_hash (sections_status);
160 	for (i = 0; i < children->len; i++) {
161 		GType          child_type;
162 		GtkWidget     *child;
163 		GtkWidget     *section;
164 		SectionStatus *status;
165 
166 		child_type = g_array_index (children, GType, i);
167 		child = g_object_new (child_type, NULL);
168 		g_return_if_fail (GTH_IS_PROPERTY_VIEW (child));
169 
170 		section = gth_sidebar_section_new (GTH_PROPERTY_VIEW (child));
171 		status = g_hash_table_lookup (status_hash, gth_sidebar_section_get_id (GTH_SIDEBAR_SECTION (section)));
172 		if (status != NULL) {
173 			gth_sidebar_section_set_expanded (GTH_SIDEBAR_SECTION (section), status->expanded);
174 		}
175 
176 		sidebar->priv->sections = g_list_prepend (sidebar->priv->sections, section);
177 		gtk_box_pack_start (GTK_BOX (sidebar->priv->properties),
178 				    section,
179 				    FALSE,
180 				    FALSE,
181 				    0);
182 	}
183 	g_hash_table_unref (status_hash);
184 
185 	sidebar->priv->sections = g_list_reverse (sidebar->priv->sections);
186 }
187 
188 
189 static void
_gth_sidebar_construct(GthSidebar * sidebar)190 _gth_sidebar_construct (GthSidebar *sidebar)
191 {
192 	GtkWidget *properties_win;
193 	GtkWidget *empty_view;
194 	GtkWidget *icon;
195 
196 	properties_win = gtk_scrolled_window_new (NULL, NULL);
197 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (properties_win), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
198 	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (properties_win), GTK_SHADOW_NONE);
199 	gtk_widget_set_vexpand (properties_win, TRUE);
200 	gtk_widget_show (properties_win);
201 	gtk_stack_add_named (GTK_STACK (sidebar), properties_win, GTH_SIDEBAR_PAGE_PROPERTIES);
202 
203 	sidebar->priv->properties = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
204 	gtk_widget_set_size_request (GTK_WIDGET (sidebar->priv->properties), MIN_SIDEBAR_WIDTH, -1);
205 	gtk_widget_show (sidebar->priv->properties);
206 	gtk_container_add (GTK_CONTAINER (properties_win), sidebar->priv->properties);
207 
208 	sidebar->priv->toolbox = gth_toolbox_new ("file-tools");
209 	gtk_style_context_add_class (gtk_widget_get_style_context (sidebar->priv->toolbox), GTK_STYLE_CLASS_SIDEBAR);
210 	gtk_widget_set_vexpand (sidebar->priv->toolbox, TRUE);
211 	gtk_widget_set_size_request (GTK_WIDGET (sidebar->priv->toolbox), MIN_SIDEBAR_WIDTH, -1);
212 	gtk_widget_show (sidebar->priv->toolbox);
213 	gtk_stack_add_named (GTK_STACK (sidebar), sidebar->priv->toolbox, GTH_SIDEBAR_PAGE_TOOLS);
214 
215 	empty_view = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
216 	gtk_widget_show (empty_view);
217 	gtk_stack_add_named (GTK_STACK (sidebar), empty_view, GTH_SIDEBAR_PAGE_EMPTY);
218 
219 	icon = gtk_image_new_from_icon_name("action-unavailable-symbolic", GTK_ICON_SIZE_DIALOG);
220 	gtk_style_context_add_class (gtk_widget_get_style_context (icon), "void-view");
221 	gtk_widget_show (icon);
222 	gtk_box_pack_start (GTK_BOX (empty_view), icon, TRUE, FALSE, 0);
223 }
224 
225 
226 GtkWidget *
gth_sidebar_new(char ** sections_status)227 gth_sidebar_new (char **sections_status)
228 {
229 	GthSidebar *sidebar;
230 
231 	sidebar = g_object_new (GTH_TYPE_SIDEBAR, NULL);
232 	_gth_sidebar_construct (sidebar);
233 	_gth_sidebar_add_sections (sidebar, sections_status);
234 
235 	return (GtkWidget *) sidebar;
236 }
237 
238 
239 GtkWidget *
gth_sidebar_get_toolbox(GthSidebar * sidebar)240 gth_sidebar_get_toolbox (GthSidebar *sidebar)
241 {
242 	return sidebar->priv->toolbox;
243 }
244 
245 
246 static void
_gth_sidebar_update_view(GthSidebar * sidebar)247 _gth_sidebar_update_view (GthSidebar  *sidebar)
248 {
249 	gtk_stack_set_visible_child_name (GTK_STACK (sidebar), (sidebar->priv->n_visibles == 0) ? GTH_SIDEBAR_PAGE_EMPTY : sidebar->priv->selected_page);
250 }
251 
252 
253 void
gth_sidebar_set_file(GthSidebar * sidebar,GthFileData * file_data)254 gth_sidebar_set_file (GthSidebar  *sidebar,
255 		      GthFileData *file_data)
256 {
257 	GList *scan;
258 
259 	if ((file_data == NULL) || ! g_file_info_get_attribute_boolean (file_data->info, "gth::file::is-modified"))
260 		gth_toolbox_deactivate_tool (GTH_TOOLBOX (sidebar->priv->toolbox));
261 
262 	_g_object_unref (sidebar->priv->file_data);
263 	sidebar->priv->file_data = gth_file_data_dup (file_data);
264 
265 	sidebar->priv->n_visibles = 0;
266 	for (scan = sidebar->priv->sections; scan; scan = scan->next) {
267 		GtkWidget *child = scan->data;
268 		if (gth_sidebar_section_set_file (GTH_SIDEBAR_SECTION (child), sidebar->priv->file_data))
269 			sidebar->priv->n_visibles++;
270 	}
271 
272 	_gth_sidebar_update_view (sidebar);
273 }
274 
275 
276 static void
_gth_sidebar_set_visible_page(GthSidebar * sidebar,const char * page)277 _gth_sidebar_set_visible_page (GthSidebar *sidebar,
278 			       const char *page)
279 {
280 	sidebar->priv->selected_page = page;
281 	gtk_stack_set_visible_child_name (GTK_STACK (sidebar), sidebar->priv->selected_page);
282 
283 	_gth_sidebar_update_view (sidebar);
284 }
285 
286 
287 void
gth_sidebar_show_properties(GthSidebar * sidebar)288 gth_sidebar_show_properties (GthSidebar *sidebar)
289 {
290 	_gth_sidebar_set_visible_page (sidebar, GTH_SIDEBAR_PAGE_PROPERTIES);
291 }
292 
293 
294 void
gth_sidebar_show_tools(GthSidebar * sidebar)295 gth_sidebar_show_tools (GthSidebar *sidebar)
296 {
297 	_gth_sidebar_set_visible_page (sidebar, GTH_SIDEBAR_PAGE_TOOLS);
298 }
299 
300 
301 gboolean
gth_sidebar_tool_is_active(GthSidebar * sidebar)302 gth_sidebar_tool_is_active (GthSidebar *sidebar)
303 {
304 	return gth_toolbox_tool_is_active (GTH_TOOLBOX (sidebar->priv->toolbox));
305 }
306 
307 
308 void
gth_sidebar_deactivate_tool(GthSidebar * sidebar)309 gth_sidebar_deactivate_tool (GthSidebar *sidebar)
310 {
311 	gth_toolbox_deactivate_tool (GTH_TOOLBOX (sidebar->priv->toolbox));
312 }
313 
314 
315 void
gth_sidebar_update_sensitivity(GthSidebar * sidebar)316 gth_sidebar_update_sensitivity (GthSidebar *sidebar)
317 {
318 	gth_toolbox_update_sensitivity (GTH_TOOLBOX (sidebar->priv->toolbox));
319 }
320 
321 
322 char **
gth_sidebar_get_sections_status(GthSidebar * sidebar)323 gth_sidebar_get_sections_status (GthSidebar *sidebar)
324 {
325 	GList  *status_list;
326 	GList  *scan;
327 	char  **result;
328 
329 	status_list = NULL;
330 	for (scan = sidebar->priv->sections; scan; scan = scan->next) {
331 		GtkWidget *section = scan->data;
332 		GString   *status;
333 
334 		status = g_string_new ("");
335 		g_string_append (status, gth_sidebar_section_get_id (GTH_SIDEBAR_SECTION (section)));
336 		g_string_append (status, STATUS_DELIMITER);
337 		g_string_append (status, gth_sidebar_section_get_expanded (GTH_SIDEBAR_SECTION (section)) ? STATUS_EXPANDED : STATUS_NOT_EXPANDED);
338 		status_list = g_list_prepend (status_list, status->str);
339 
340 		g_string_free (status, FALSE);
341 	}
342 	status_list = g_list_reverse (status_list);
343 
344 	result = _g_string_list_to_strv (status_list);
345 	_g_string_list_free (status_list);
346 
347 	return result;
348 }
349