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