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
G_DEFINE_TYPE(RBSyncStateUI,rb_sync_state_ui,GTK_TYPE_BOX)57 G_DEFINE_TYPE (RBSyncStateUI, rb_sync_state_ui, GTK_TYPE_BOX)
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
rb_sync_state_ui_create_bar(RBSyncBarData * bar,guint64 capacity,GtkWidget * label)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
rb_sync_state_ui_update_volume_usage(RBSyncBarData * bar,RBSyncState * state)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
update_sync_after_bar(RBSyncBarData * bar,RBSyncState * state)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
sync_state_updated(RBSyncState * state,RBSyncStateUI * ui)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 *
rb_sync_state_ui_new(RBSyncState * state)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
rb_sync_state_ui_init(RBSyncStateUI * ui)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 gtk_orientable_set_orientation (GTK_ORIENTABLE (ui), GTK_ORIENTATION_VERTICAL);
218 }
219
220 static void
build_ui(RBSyncStateUI * ui)221 build_ui (RBSyncStateUI *ui)
222 {
223 RBMediaPlayerSource *source;
224 GtkWidget *widget;
225 GtkWidget *container;
226 guint64 capacity;
227 GtkBuilder *builder;
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 builder = rb_builder_load ("sync-state.ui", NULL);
234 if (builder == NULL) {
235 g_warning ("Couldn't load sync-state.ui");
236 return;
237 }
238
239 container = GTK_WIDGET (gtk_builder_get_object (builder, "sync-state-ui"));
240 gtk_box_pack_start (GTK_BOX (ui), container, TRUE, TRUE, 0);
241
242 ui->priv->add_count = GTK_WIDGET (gtk_builder_get_object (builder, "added-tracks"));
243 ui->priv->remove_count = GTK_WIDGET (gtk_builder_get_object (builder, "removed-tracks"));
244
245 widget = GTK_WIDGET (gtk_builder_get_object (builder, "sync-before-label"));
246 rb_sync_state_ui_create_bar (&ui->priv->sync_before, capacity, widget);
247 container = GTK_WIDGET (gtk_builder_get_object (builder, "sync-before-container"));
248 gtk_container_add (GTK_CONTAINER (container), ui->priv->sync_before.widget);
249
250 widget = GTK_WIDGET (gtk_builder_get_object (builder, "sync-after-label"));
251 rb_sync_state_ui_create_bar (&ui->priv->sync_after, capacity, widget);
252 container = GTK_WIDGET (gtk_builder_get_object (builder, "sync-after-container"));
253 gtk_container_add (GTK_CONTAINER (container), ui->priv->sync_after.widget);
254
255 g_object_unref (builder);
256 }
257
258 static void
impl_constructed(GObject * object)259 impl_constructed (GObject *object)
260 {
261 RBSyncStateUI *ui = RB_SYNC_STATE_UI (object);
262
263 build_ui (ui);
264 sync_state_updated (ui->priv->state, ui);
265
266 g_signal_connect_object (ui->priv->state,
267 "updated",
268 G_CALLBACK (sync_state_updated),
269 ui, 0);
270
271 RB_CHAIN_GOBJECT_METHOD(rb_sync_state_ui_parent_class, constructed, object);
272 }
273
274
275 static void
impl_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)276 impl_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
277 {
278 RBSyncStateUI *ui = RB_SYNC_STATE_UI (object);
279 switch (prop_id) {
280 case PROP_SYNC_STATE:
281 ui->priv->state = g_value_get_object (value);
282 break;
283 default:
284 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
285 break;
286 }
287 }
288
289 static void
impl_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)290 impl_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
291 {
292 RBSyncStateUI *ui = RB_SYNC_STATE_UI (object);
293 switch (prop_id) {
294 case PROP_SYNC_STATE:
295 g_value_set_object (value, ui->priv->state);
296 break;
297 default:
298 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
299 break;
300 }
301 }
302
303
304 static void
rb_sync_state_ui_class_init(RBSyncStateUIClass * klass)305 rb_sync_state_ui_class_init (RBSyncStateUIClass *klass)
306 {
307 GObjectClass *object_class = G_OBJECT_CLASS (klass);
308
309 object_class->constructed = impl_constructed;
310 object_class->set_property = impl_set_property;
311 object_class->get_property = impl_get_property;
312
313 g_object_class_install_property (object_class,
314 PROP_SYNC_STATE,
315 g_param_spec_object ("sync-state",
316 "sync-state",
317 "RBSyncState instance",
318 RB_TYPE_SYNC_STATE,
319 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
320
321 g_type_class_add_private (object_class, sizeof (RBSyncStateUIPrivate));
322 }
323