Added first logo proposal for frogr
[frogr:mainline.git] / src / frogr-main-window.c
1 /*
2  * frogr-main-window.c -- Main window for the application
3  *
4  * Copyright (C) 2009 Mario Sanchez Prada
5  * Authors: Mario Sanchez Prada <msanchez@igalia.com>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of version 3 of the GNU General Public
9  * License as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this program; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  *
21  */
22
23 #include <config.h>
24 #include "frogr-main-window.h"
25 #include "frogr-controller.h"
26 #include "frogr-picture.h"
27
28 #define MINIMUM_WINDOW_WIDTH 400
29 #define MINIMUM_WINDOW_HEIGHT 300
30
31 #define ITEM_WIDTH 120
32
33 #define THUMBNAIL_MAX_WIDTH 100
34 #define THUMBNAIL_MAX_HEIGHT 100
35
36 #define PULSE_INTERVAL 125
37
38 #define GTKBUILDER_FILE                                 \
39   APP_DATA_DIR "/gtkbuilder/frogr-main-window.xml"
40
41 #define MAIN_WINDOW_ICON PIXMAP_DIR "/frogr.xpm"
42
43 enum {
44   FILEPATH_COL,
45   PIXBUF_COL
46 };
47
48 #define FROGR_MAIN_WINDOW_GET_PRIVATE(object)                   \
49   (G_TYPE_INSTANCE_GET_PRIVATE ((object),                       \
50                                 FROGR_TYPE_MAIN_WINDOW,         \
51                                 FrogrMainWindowPrivate))
52
53 G_DEFINE_TYPE (FrogrMainWindow, frogr_main_window, GTK_TYPE_WINDOW);
54
55 typedef struct _FrogrMainWindowPrivate {
56   FrogrController *controller;
57   GtkWidget *icon_view;
58   GtkWidget *progress_bar;
59   GtkWidget *upload_button;
60   GtkWidget *auth_button;
61   GtkTreeModel *model;
62 } FrogrMainWindowPrivate;
63
64
65 /* Private API */
66
67 static void
68 _add_picture_to_icon_view (FrogrMainWindow *fmainwin,
69                            const gchar *filepath)
70 {
71   FrogrMainWindowPrivate *priv = FROGR_MAIN_WINDOW_GET_PRIVATE (fmainwin);
72   GdkPixbuf *pixbuf;
73   GdkPixbuf *scaled_pixbuf;
74   GtkTreeIter iter;
75   int width;
76   int height;
77   int new_width;
78   int new_height;
79
80   pixbuf = gdk_pixbuf_new_from_file (filepath, NULL);
81   width = gdk_pixbuf_get_width (pixbuf);
82   height = gdk_pixbuf_get_height (pixbuf);
83
84   /* Look for the right side to reduce */
85   if (width > height)
86     {
87       new_width = THUMBNAIL_MAX_WIDTH;
88       new_height = (float)new_width * height / width;
89     }
90   else
91     {
92       new_height = THUMBNAIL_MAX_HEIGHT;
93       new_width = (float)new_height * width / height;
94     }
95
96   scaled_pixbuf = gdk_pixbuf_scale_simple (pixbuf,
97                                            new_width,
98                                            new_height,
99                                            GDK_INTERP_TILES);
100
101   gtk_list_store_append (GTK_LIST_STORE (priv -> model), &iter);
102   gtk_list_store_set (GTK_LIST_STORE (priv -> model), &iter,
103                       FILEPATH_COL, filepath,
104                       PIXBUF_COL, scaled_pixbuf,
105                       -1);
106
107   /* Free original pixbuf */
108   g_object_unref (pixbuf);
109 }
110
111 static void
112 _update_ui (FrogrMainWindow *fmainwin)
113 {
114   FrogrMainWindowPrivate *priv = FROGR_MAIN_WINDOW_GET_PRIVATE (fmainwin);
115   FrogrControllerState state;
116
117   /* Set sensitiveness */
118   state = frogr_controller_get_state (priv -> controller);
119   if (state ==  FROGR_CONTROLLER_UPLOADING)
120     {
121       gtk_widget_set_sensitive (priv -> upload_button, FALSE);
122       gtk_widget_set_sensitive (priv -> auth_button, FALSE);
123     }
124   else
125     {
126       gboolean authorized;
127
128       authorized = frogr_controller_is_authorized (priv -> controller);
129       gtk_widget_set_sensitive (priv -> upload_button, authorized);
130       gtk_widget_set_sensitive (priv -> auth_button, !authorized);
131     }
132 }
133
134 /* Event handlers */
135 void
136 _on_add_button_clicked (GtkButton *widget,
137                         gpointer data)
138 {
139   FrogrMainWindow *fmainwin = FROGR_MAIN_WINDOW (data);
140   FrogrMainWindowPrivate *priv = FROGR_MAIN_WINDOW_GET_PRIVATE (data);
141   GtkWidget *dialog;
142   GtkFileFilter *filter;
143
144   dialog = gtk_file_chooser_dialog_new ("Select a picture",
145                                         GTK_WINDOW (fmainwin),
146                                         GTK_FILE_CHOOSER_ACTION_OPEN,
147                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
148                                         GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
149                                         NULL);
150
151   /* Set images filter */
152   filter = gtk_file_filter_new ();
153   gtk_file_filter_add_mime_type (filter, "image/jpeg");
154   gtk_file_filter_add_mime_type (filter, "image/png");
155   gtk_file_filter_add_mime_type (filter, "image/bmp");
156   gtk_file_filter_add_mime_type (filter, "image/gif");
157   gtk_file_filter_set_name (filter, "images");
158   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
159   gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
160
161   if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
162     {
163       GSList *filenames;
164       GSList *item;
165
166       /* Add selected pictures to icon view area */
167       filenames = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (dialog));
168       for (item = filenames; item; item = g_slist_next (item))
169         {
170           gchar *filepath = (gchar *)(item -> data);
171
172           g_debug ("Filename %s selected!\n", filepath);
173           _add_picture_to_icon_view (fmainwin, filepath);
174         }
175
176       /* Free memory */
177       g_slist_foreach (filenames, (GFunc)g_free, NULL);
178       g_slist_free (filenames);
179     }
180
181   /* Close dialog */
182   gtk_widget_destroy (dialog);
183 }
184
185 void
186 _on_remove_button_clicked (GtkButton *widget,
187                            gpointer data)
188 {
189   FrogrMainWindow *fmainwin = FROGR_MAIN_WINDOW (data);
190   FrogrMainWindowPrivate *priv = FROGR_MAIN_WINDOW_GET_PRIVATE (data);
191   GList *selected_items;
192   GList *item;
193
194   /* Remove selected items */
195   selected_items = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (priv -> icon_view));
196   for (item = selected_items; item; item = g_list_next (item))
197     {
198       GtkTreePath *path;
199       GtkTreeIter iter;
200
201       /* Remove selected element */
202       path = (GtkTreePath *)(item -> data);
203       gtk_tree_model_get_iter (priv -> model, &iter, path);
204       gtk_list_store_remove (GTK_LIST_STORE (priv -> model), &iter);
205     }
206
207   /* Free */
208   g_list_foreach (selected_items, (GFunc)gtk_tree_path_free, NULL);
209   g_list_free (selected_items);
210 }
211
212 void
213 _on_auth_button_clicked (GtkButton *widget,
214                          gpointer data)
215 {
216   FrogrMainWindow *fmainwin = FROGR_MAIN_WINDOW (data);
217   FrogrMainWindowPrivate *priv = FROGR_MAIN_WINDOW_GET_PRIVATE (data);
218
219   /* Delegate on controller and update UI */
220   frogr_controller_show_auth_dialog (priv -> controller);
221   _update_ui (fmainwin);
222 }
223
224 void
225 _on_upload_button_clicked (GtkButton *widget,
226                            gpointer data)
227 {
228   FrogrMainWindow *fmainwin = FROGR_MAIN_WINDOW (data);
229   FrogrMainWindowPrivate *priv = FROGR_MAIN_WINDOW_GET_PRIVATE (data);
230   GtkTreeIter iter;
231   GSList *gfpictures = NULL;
232   gboolean valid = FALSE;
233
234   /* Build a simple list of pictures */
235   valid = gtk_tree_model_get_iter_first (priv -> model, &iter);
236   while (valid)
237     {
238       gchar *filepath;
239
240       /* Get needed information */
241       gtk_tree_model_get (priv -> model,
242                           &iter,
243                           FILEPATH_COL, &filepath,
244                           -1);
245
246       if (filepath)
247         {
248           g_debug ("File chosen! %s", filepath);
249
250           /* Build a new picture to be uploaded */
251           gchar *filename = g_path_get_basename (filepath);
252
253           FrogrPicture *gfpicture =
254             frogr_picture_new (filename,
255                                filepath,
256                                FALSE);
257
258           /* Add picture */
259           gfpictures = g_slist_append (gfpictures, gfpicture);
260
261           /* Free */
262           g_free (filepath);
263           g_free (filename);
264         }
265
266       /* Iterate over the nex element */
267       valid = gtk_tree_model_iter_next (priv -> model, &iter);
268     }
269
270   /* Upload pictures */
271   frogr_controller_upload_pictures (priv -> controller, gfpictures);
272 }
273
274 gboolean
275 _on_main_window_delete_event (GtkWidget *widget,
276                               GdkEvent *event,
277                               gpointer fmainwin)
278 {
279   FrogrMainWindowPrivate *priv = FROGR_MAIN_WINDOW_GET_PRIVATE (fmainwin);
280   frogr_controller_quit_app (priv -> controller);
281   return TRUE;
282 }
283
284 void
285 _on_quit_menu_item_activate (GtkWidget *widget, gpointer fmainwin)
286 {
287   FrogrMainWindowPrivate *priv = \
288     FROGR_MAIN_WINDOW_GET_PRIVATE (fmainwin);
289
290   frogr_controller_quit_app (priv -> controller);
291 }
292
293 void
294 _on_about_menu_item_activate (GtkWidget *widget, gpointer fmainwin)
295 {
296   FrogrMainWindowPrivate *priv = \
297     FROGR_MAIN_WINDOW_GET_PRIVATE (fmainwin);
298
299   /* Run the about dialog */
300   frogr_controller_show_about_dialog (priv -> controller);
301 }
302
303 static void
304 _frogr_main_window_finalize (GObject *object)
305 {
306   FrogrMainWindowPrivate *priv = FROGR_MAIN_WINDOW_GET_PRIVATE (object);
307   g_object_unref (priv -> controller);
308   G_OBJECT_CLASS(frogr_main_window_parent_class) -> finalize (object);
309 }
310
311 static void
312 frogr_main_window_class_init (FrogrMainWindowClass *klass)
313 {
314   GObjectClass *obj_class = (GObjectClass *)klass;
315
316   obj_class -> finalize = _frogr_main_window_finalize;
317   g_type_class_add_private (obj_class, sizeof (FrogrMainWindowPrivate));
318 }
319
320 static void
321 frogr_main_window_init (FrogrMainWindow *fmainwin)
322 {
323   FrogrMainWindowPrivate *priv = FROGR_MAIN_WINDOW_GET_PRIVATE (fmainwin);
324   GtkBuilder *builder;
325   GtkWidget *vbox;
326   GtkWidget *auth_button;
327   GtkWidget *upload_button;
328   GtkWidget *icon_view;
329   GtkWidget *progress_bar;
330   gboolean authorized;
331
332   /* Save a reference to the controller */
333   priv -> controller = frogr_controller_get_instance ();
334
335   /* Create widgets */
336   builder = gtk_builder_new ();
337   gtk_builder_add_from_file (builder, GTKBUILDER_FILE, NULL);
338
339   vbox = GTK_WIDGET (gtk_builder_get_object (builder, "main_window_vbox"));
340   gtk_widget_reparent (vbox, GTK_WIDGET (fmainwin));
341
342   icon_view = GTK_WIDGET (gtk_builder_get_object (builder, "icon_view"));
343   priv -> icon_view = icon_view;
344
345   progress_bar = GTK_WIDGET (gtk_builder_get_object (builder, "progress_bar"));
346   priv -> progress_bar = progress_bar;
347
348   upload_button = GTK_WIDGET (gtk_builder_get_object (builder, "upload_button"));
349   priv -> upload_button = upload_button;
350
351   auth_button = GTK_WIDGET (gtk_builder_get_object (builder, "auth_button"));
352   priv -> auth_button = auth_button;
353
354   /* Initialize model */
355   priv -> model = GTK_TREE_MODEL (gtk_list_store_new (2, G_TYPE_STRING, GDK_TYPE_PIXBUF));
356   gtk_icon_view_set_model (GTK_ICON_VIEW (icon_view), priv -> model);
357   gtk_icon_view_set_pixbuf_column (GTK_ICON_VIEW (icon_view), PIXBUF_COL);
358   gtk_icon_view_set_selection_mode (GTK_ICON_VIEW (icon_view), GTK_SELECTION_MULTIPLE);
359   gtk_icon_view_set_columns (GTK_ICON_VIEW (icon_view), -1);
360   gtk_icon_view_set_item_width (GTK_ICON_VIEW (icon_view), ITEM_WIDTH);
361
362   gtk_window_set_icon_from_file(GTK_WINDOW (fmainwin), MAIN_WINDOW_ICON, NULL);
363   gtk_window_set_default_size (GTK_WINDOW (fmainwin),
364                                MINIMUM_WINDOW_WIDTH,
365                                MINIMUM_WINDOW_HEIGHT);
366
367   /* Connect signals */
368   g_signal_connect (G_OBJECT (fmainwin), "destroy",
369                     G_CALLBACK (gtk_main_quit),
370                     NULL);
371
372   g_signal_connect (G_OBJECT (fmainwin), "delete-event",
373                     G_CALLBACK (_on_main_window_delete_event),
374                     fmainwin);
375
376   gtk_builder_connect_signals (builder, fmainwin);
377
378   /* Show the UI */
379   _update_ui (fmainwin);
380   gtk_widget_show_all (GTK_WIDGET(fmainwin));
381
382   g_object_unref (G_OBJECT (builder));
383 }
384
385
386 /* Public API */
387
388 FrogrMainWindow *
389 frogr_main_window_new (void)
390 {
391   GObject *new = g_object_new (FROGR_TYPE_MAIN_WINDOW,
392                                "type", GTK_WINDOW_TOPLEVEL,
393                                NULL);
394   return FROGR_MAIN_WINDOW (new);
395 }
396
397 static gboolean
398 _pulse_activity_progress_bar (gpointer data)
399 {
400   FrogrMainWindowPrivate *priv = FROGR_MAIN_WINDOW_GET_PRIVATE (data);
401   FrogrControllerState state;
402
403   state = frogr_controller_get_state (priv -> controller);
404   if (state != FROGR_CONTROLLER_UPLOADING)
405     return FALSE;
406
407   /* Pulse and wait for another pulse */
408   gtk_progress_bar_pulse (GTK_PROGRESS_BAR (priv -> progress_bar));
409   return TRUE;
410 }
411
412 void
413 frogr_main_window_notify_state_changed (FrogrMainWindow *fmainwin)
414 {
415   g_return_if_fail(FROGR_IS_MAIN_WINDOW (fmainwin));
416
417   FrogrMainWindowPrivate *priv = FROGR_MAIN_WINDOW_GET_PRIVATE (fmainwin);
418   FrogrControllerState state;
419
420   state = frogr_controller_get_state (priv -> controller);
421   if (state ==  FROGR_CONTROLLER_UPLOADING)
422     {
423       g_timeout_add (PULSE_INTERVAL,
424                      (GSourceFunc)_pulse_activity_progress_bar,
425                      fmainwin);
426     }
427   else
428     {
429       /* Return progress bar to normal mode if not uploading anymore */
430       g_object_set (priv -> progress_bar, "activity-mode", FALSE, NULL);
431     }
432
433   /* Update UI */
434   _update_ui (fmainwin);
435 }