No issues found
1 /*
2 * Copyright (C) 2010 Jonathan Matthew <jonathan@d14n.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * The Rhythmbox authors hereby grant permission for non-GPL compatible
10 * GStreamer plugins to be used and distributed together with GStreamer
11 * and Rhythmbox. This permission is above and beyond the permissions granted
12 * by the GPL license by which Rhythmbox is covered. If you modify this code
13 * you may extend this exception to your version of the code, but you are not
14 * obligated to do so. If you do not wish to do so, delete this exception
15 * statement from your version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
25 *
26 */
27
28 #include "config.h"
29
30 #include <glib/gi18n.h>
31
32 #include "rb-sync-state-ui.h"
33 #include "rb-debug.h"
34 #include "rb-util.h"
35 #include "rb-file-helpers.h"
36 #include "rb-builder-helpers.h"
37
38 #include "rb-segmented-bar.h"
39
40 struct _RBSyncStateUIPrivate
41 {
42 /* we don't own a reference on this (maybe we should?) */
43 RBSyncState *state;
44
45 /* or any of these */
46 GtkWidget *add_count;
47 GtkWidget *remove_count;
48 RBSyncBarData sync_before;
49 RBSyncBarData sync_after;
50 };
51
52 enum {
53 PROP_0,
54 PROP_SYNC_STATE
55 };
56
57 G_DEFINE_TYPE (RBSyncStateUI, rb_sync_state_ui, GTK_TYPE_VBOX)
58
59
60 static char *
61 value_formatter (gdouble percent, RBSyncBarData *bar)
62 {
63 return g_format_size (percent * bar->capacity);
64 }
65
66 void
67 rb_sync_state_ui_create_bar (RBSyncBarData *bar, guint64 capacity, GtkWidget *label)
68 {
69 bar->widget = rb_segmented_bar_new ();
70 bar->capacity = capacity;
71 g_object_set (bar->widget, "show-labels", TRUE, NULL);
72
73 rb_segmented_bar_set_value_formatter (RB_SEGMENTED_BAR (bar->widget),
74 (RBSegmentedBarValueFormatter) value_formatter,
75 bar);
76
77 bar->music_segment = rb_segmented_bar_add_segment (RB_SEGMENTED_BAR (bar->widget),_("Music"), 0.0, 0.2, 0.4, 0.65, 1.0);
78 bar->podcast_segment = rb_segmented_bar_add_segment (RB_SEGMENTED_BAR (bar->widget), _("Podcasts"), 0.0, 0.96, 0.47, 0.0, 1.0);
79 bar->other_segment = rb_segmented_bar_add_segment (RB_SEGMENTED_BAR (bar->widget), _("Other"), 0.0, 0.45, 0.82, 0.08, 1.0);
80 bar->free_segment = rb_segmented_bar_add_segment_default_color (RB_SEGMENTED_BAR (bar->widget), _("Available"), 1.0);
81
82 /* set up label relationship */
83 if (label != NULL) {
84 AtkObject *lobj;
85 AtkObject *robj;
86
87 lobj = gtk_widget_get_accessible (label);
88 robj = gtk_widget_get_accessible (bar->widget);
89
90 atk_object_add_relationship (lobj, ATK_RELATION_LABEL_FOR, robj);
91 atk_object_add_relationship (robj, ATK_RELATION_LABELLED_BY, lobj);
92 }
93 }
94
95
96 void
97 rb_sync_state_ui_update_volume_usage (RBSyncBarData *bar, RBSyncState *state)
98 {
99 RBMediaPlayerSource *source;
100 double fraction;
101 guint64 total_other;
102 guint64 free_space;
103
104 g_object_get (state, "source", &source, NULL);
105 free_space = rb_media_player_source_get_free_space (source);
106 g_object_unref (source);
107
108 total_other = bar->capacity - (free_space + state->total_music_size + state->total_podcast_size);
109
110 fraction = (double)state->total_music_size/(double)bar->capacity;
111 rb_segmented_bar_update_segment (RB_SEGMENTED_BAR (bar->widget),
112 bar->music_segment,
113 fraction);
114 fraction = (double)state->total_podcast_size/(double)bar->capacity;
115 rb_segmented_bar_update_segment (RB_SEGMENTED_BAR (bar->widget),
116 bar->podcast_segment,
117 fraction);
118 fraction = (double)total_other/(double)bar->capacity;
119 rb_segmented_bar_update_segment (RB_SEGMENTED_BAR (bar->widget),
120 bar->other_segment,
121 fraction);
122 fraction = (double)free_space/(double)bar->capacity;
123 rb_segmented_bar_update_segment (RB_SEGMENTED_BAR (bar->widget),
124 bar->free_segment,
125 fraction);
126 }
127
128 static void
129 update_sync_after_bar (RBSyncBarData *bar, RBSyncState *state)
130 {
131 RBMediaPlayerSource *source;
132 RBSyncSettings *settings;
133 double music_fraction;
134 double podcast_fraction;
135 double other_fraction;
136 double free_fraction;
137 guint64 total_other_size;
138
139 g_object_get (state,
140 "source", &source,
141 "sync-settings", &settings,
142 NULL);
143
144 if (rb_sync_settings_has_enabled_groups (settings, SYNC_CATEGORY_MUSIC) ||
145 rb_sync_settings_sync_category (settings, SYNC_CATEGORY_MUSIC)) {
146 music_fraction = (double)state->sync_music_size / (double)bar->capacity;
147 } else {
148 music_fraction = (double)state->total_music_size / (double)bar->capacity;
149 }
150 if (rb_sync_settings_has_enabled_groups (settings, SYNC_CATEGORY_PODCAST) ||
151 rb_sync_settings_sync_category (settings, SYNC_CATEGORY_PODCAST)) {
152 podcast_fraction = (double)state->sync_podcast_size / (double)bar->capacity;
153 } else {
154 podcast_fraction = (double)state->total_podcast_size / (double)bar->capacity;
155 }
156
157 total_other_size = bar->capacity - (rb_media_player_source_get_free_space (source) + state->total_music_size + state->total_podcast_size);
158 other_fraction = (double)total_other_size / (double)bar->capacity;
159
160 free_fraction = 1.0 - (music_fraction + podcast_fraction + other_fraction);
161 if (free_fraction < 0.0) {
162 free_fraction = 0.0;
163 }
164
165 rb_segmented_bar_update_segment (RB_SEGMENTED_BAR (bar->widget),
166 bar->music_segment,
167 music_fraction);
168 rb_segmented_bar_update_segment (RB_SEGMENTED_BAR (bar->widget),
169 bar->podcast_segment,
170 podcast_fraction);
171 rb_segmented_bar_update_segment (RB_SEGMENTED_BAR (bar->widget),
172 bar->other_segment,
173 other_fraction);
174 rb_segmented_bar_update_segment (RB_SEGMENTED_BAR (bar->widget),
175 bar->free_segment,
176 free_fraction);
177
178 g_object_unref (source);
179 g_object_unref (settings);
180 }
181
182 static void
183 sync_state_updated (RBSyncState *state, RBSyncStateUI *ui)
184 {
185 char *text;
186 rb_debug ("sync state updated");
187
188 /* sync before state */
189 rb_sync_state_ui_update_volume_usage (&ui->priv->sync_before, state);
190 update_sync_after_bar (&ui->priv->sync_after, state);
191
192 /* other stuff */
193 text = g_strdup_printf ("%d", state->sync_add_count);
194 gtk_label_set_text (GTK_LABEL (ui->priv->add_count), text);
195 g_free (text);
196
197 text = g_strdup_printf ("%d", state->sync_remove_count);
198 gtk_label_set_text (GTK_LABEL (ui->priv->remove_count), text);
199 g_free (text);
200 }
201
202
203 GtkWidget *
204 rb_sync_state_ui_new (RBSyncState *state)
205 {
206 GObject *ui;
207 ui = g_object_new (RB_TYPE_SYNC_STATE_UI,
208 "sync-state", state,
209 NULL);
210 return GTK_WIDGET (ui);
211 }
212
213 static void
214 rb_sync_state_ui_init (RBSyncStateUI *ui)
215 {
216 ui->priv = G_TYPE_INSTANCE_GET_PRIVATE (ui, RB_TYPE_SYNC_STATE_UI, RBSyncStateUIPrivate);
217 }
218
219 static void
220 build_ui (RBSyncStateUI *ui)
221 {
222 RBMediaPlayerSource *source;
223 GtkWidget *widget;
224 GtkWidget *container;
225 guint64 capacity;
226 GtkBuilder *builder;
227 const char *ui_file;
228
229 g_object_get (ui->priv->state, "source", &source, NULL);
230 capacity = rb_media_player_source_get_capacity (source);
231 g_object_unref (source);
232
233 ui_file = rb_file ("sync-state.ui");
234 if (ui_file == NULL) {
235 g_warning ("Couldn't find sync-state.ui");
236 return;
237 }
238
239 builder = rb_builder_load (ui_file, NULL);
240 if (builder == NULL) {
241 g_warning ("Couldn't load sync-state.ui");
242 return;
243 }
244
245 container = GTK_WIDGET (gtk_builder_get_object (builder, "sync-state-ui"));
246 gtk_box_pack_start (GTK_BOX (ui), container, TRUE, TRUE, 0);
247
248 ui->priv->add_count = GTK_WIDGET (gtk_builder_get_object (builder, "added-tracks"));
249 ui->priv->remove_count = GTK_WIDGET (gtk_builder_get_object (builder, "removed-tracks"));
250
251 widget = GTK_WIDGET (gtk_builder_get_object (builder, "sync-before-label"));
252 rb_sync_state_ui_create_bar (&ui->priv->sync_before, capacity, widget);
253 container = GTK_WIDGET (gtk_builder_get_object (builder, "sync-before-container"));
254 gtk_container_add (GTK_CONTAINER (container), ui->priv->sync_before.widget);
255
256 widget = GTK_WIDGET (gtk_builder_get_object (builder, "sync-after-label"));
257 rb_sync_state_ui_create_bar (&ui->priv->sync_after, capacity, widget);
258 container = GTK_WIDGET (gtk_builder_get_object (builder, "sync-after-container"));
259 gtk_container_add (GTK_CONTAINER (container), ui->priv->sync_after.widget);
260
261 g_object_unref (builder);
262 }
263
264 static void
265 impl_constructed (GObject *object)
266 {
267 RBSyncStateUI *ui = RB_SYNC_STATE_UI (object);
268
269 build_ui (ui);
270 sync_state_updated (ui->priv->state, ui);
271
272 g_signal_connect_object (ui->priv->state,
273 "updated",
274 G_CALLBACK (sync_state_updated),
275 ui, 0);
276
277 RB_CHAIN_GOBJECT_METHOD(rb_sync_state_ui_parent_class, constructed, object);
278 }
279
280
281 static void
282 impl_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
283 {
284 RBSyncStateUI *ui = RB_SYNC_STATE_UI (object);
285 switch (prop_id) {
286 case PROP_SYNC_STATE:
287 ui->priv->state = g_value_get_object (value);
288 break;
289 default:
290 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
291 break;
292 }
293 }
294
295 static void
296 impl_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
297 {
298 RBSyncStateUI *ui = RB_SYNC_STATE_UI (object);
299 switch (prop_id) {
300 case PROP_SYNC_STATE:
301 g_value_set_object (value, ui->priv->state);
302 break;
303 default:
304 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
305 break;
306 }
307 }
308
309
310 static void
311 rb_sync_state_ui_class_init (RBSyncStateUIClass *klass)
312 {
313 GObjectClass *object_class = G_OBJECT_CLASS (klass);
314
315 object_class->constructed = impl_constructed;
316 object_class->set_property = impl_set_property;
317 object_class->get_property = impl_get_property;
318
319 g_object_class_install_property (object_class,
320 PROP_SYNC_STATE,
321 g_param_spec_object ("sync-state",
322 "sync-state",
323 "RBSyncState instance",
324 RB_TYPE_SYNC_STATE,
325 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
326
327 g_type_class_add_private (object_class, sizeof (RBSyncStateUIPrivate));
328 }