progress.c

Go to the documentation of this file.
00001 /*****************************************************************************
00002  *
00003  * cdebconf - An implementation of the Debian Configuration Management
00004  *            System
00005  *
00006  * $Id$
00007  *
00008  * cdebconf is (c) 2000-2007 Randolph Chung and others under the following
00009  * license.
00010  *
00011  * Redistribution and use in source and binary forms, with or without
00012  * modification, are permitted provided that the following conditions
00013  * are met:
00014  *
00015  * 1. Redistributions of source code must retain the above copyright
00016  * notice, this list of conditions and the following disclaimer.
00017  *
00018  * 2. Redistributions in binary form must reproduce the above copyright
00019  * notice, this list of conditions and the following disclaimer in the
00020  * documentation and/or other materials provided with the distribution.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
00023  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00025  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
00026  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00027  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00028  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00029  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00031  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00032  * SUCH DAMAGE.
00033  *
00034  *****************************************************************************/
00035 
00040 #include "progress.h"
00041 
00042 #include <string.h>
00043 #include <glib.h>
00044 #include <gdk/gdkkeysyms.h>
00045 #include <gtk/gtk.h>
00046 
00047 #include "frontend.h"
00048 
00049 #include "fe_gtk.h"
00050 #include "fe_data.h"
00051 #include "ui.h"
00052 #ifdef DI_UDEB
00053 # include "di.h"
00054 #endif /* DI_UDEB */
00055 
00057 #define PROGRESSBAR_HPADDING 60
00058 
00059 #define PROGRESSBAR_VPADDING 60
00060 
00065 struct progress_data {
00067     struct frontend * fe;
00068 
00070     GtkWidget * progress_bar; 
00071 
00073     GtkWidget * progress_label;
00074 
00076     GtkWidget * progress_box;
00077 
00082     GtkWidget * cancel_button;
00083 };
00084 
00090 static void create_progress_bar(struct progress_data * progress_data,
00091                                 GtkWidget * container)
00092 {
00093     GtkWidget * progress_bar;
00094 
00095     /* XXX: check NULL! */
00096     progress_bar = gtk_progress_bar_new();
00097 
00098     gtk_progress_bar_set_ellipsize(GTK_PROGRESS_BAR(progress_bar),
00099                                    PANGO_ELLIPSIZE_MIDDLE);
00100 
00101     gtk_box_pack_start(GTK_BOX(container), progress_bar,
00102                        FALSE /* don't expand */,
00103                        FALSE /* don't fill */, 0 /* padding */);
00104     
00105     g_object_ref(G_OBJECT(progress_bar));
00106     progress_data->progress_bar = progress_bar;
00107 }
00108 
00115 static void destroy_progress_bar(struct progress_data * progress_data)
00116 {
00117     GtkWidget * progress_bar = progress_data->progress_bar;
00118 
00119     if (NULL != progress_bar) {
00120         progress_data->progress_bar = NULL;
00121         g_object_unref(progress_bar);
00122         /* widget will be destroyed by destroy_progress_box */
00123     }
00124 }
00125 
00131 static void create_progress_label(struct progress_data * progress_data,
00132                                   GtkWidget * container)
00133 {
00134     GtkWidget * progress_label;
00135 
00136     /* XXX: check null! */
00137     progress_label = gtk_label_new(NULL /* no text */);
00138 
00139     gtk_misc_set_alignment(GTK_MISC(progress_label),
00140                            0 /* left */, 0 /* top */);
00141 
00142     gtk_box_pack_start(GTK_BOX(container), progress_label,
00143                        FALSE /* don't expand */, FALSE /* don't fill */,
00144                        DEFAULT_PADDING);
00145 
00146     g_object_ref(G_OBJECT(progress_label));
00147     progress_data->progress_label = progress_label;
00148 }
00149 
00156 static void destroy_progress_label(struct progress_data * progress_data)
00157 {
00158     GtkWidget * progress_label = progress_data->progress_label;
00159 
00160     if (NULL != progress_label) {
00161         progress_data->progress_label = NULL;
00162         g_object_unref(progress_label);
00163         /* widget will be destroyed by destroy_progress_box */
00164     }
00165 }
00166 
00172 static void create_progress_box(struct progress_data * progress_data)
00173 {
00174     GtkWidget * progress_box;
00175 
00176     /* check NULL! */
00177     progress_box = gtk_vbox_new(FALSE /* don't make children equal */,
00178                                 0 /* padding */);
00179 
00180     create_progress_bar(progress_data, progress_box);
00181     create_progress_label(progress_data, progress_box);
00182 
00183     fe_gtk_center_widget(&progress_box, PROGRESSBAR_HPADDING,
00184                          PROGRESSBAR_VPADDING);
00185 
00186     g_object_ref(G_OBJECT(progress_box));
00187     progress_data->progress_box = progress_box;
00188 }
00189 
00196 static void destroy_progress_box(struct progress_data * progress_data)
00197 {
00198     GtkWidget * progress_box = progress_data->progress_box;
00199 
00200     if (NULL != progress_box) {
00201         progress_data->progress_box = NULL;
00202         g_object_unref(progress_box);
00203         gtk_widget_destroy(progress_box);
00204     }
00205     destroy_progress_label(progress_data);
00206     destroy_progress_bar(progress_data);
00207 }
00208 
00216 void fe_gtk_show_progress(struct frontend * fe)
00217 {
00218     struct frontend_data * fe_data = fe->data;
00219     struct progress_data * progress_data = fe_data->progress_data;
00220 
00221     g_assert(NULL != progress_data);
00222     if (NULL == gtk_widget_get_parent(progress_data->progress_box)) {
00223         gtk_box_pack_start(
00224             GTK_BOX(fe_data->target_box), progress_data->progress_box,
00225             FALSE /* don't expand */, FALSE /* don't fill */, DEFAULT_PADDING);
00226     }
00227     if (NULL != progress_data->cancel_button &&
00228         NULL == gtk_widget_get_parent(progress_data->cancel_button)) {
00229         gtk_box_pack_start(
00230             GTK_BOX(fe_data->action_box), progress_data->cancel_button,
00231             TRUE /* expand */, TRUE /* fill */, DEFAULT_PADDING);
00232     }
00233     gtk_widget_show_all(progress_data->progress_box);
00234     gtk_widget_show_all(fe_data->action_box);
00235 }
00236 
00245 void fe_gtk_hide_progress(struct frontend * fe)
00246 {
00247     struct frontend_data * fe_data = fe->data;
00248     struct progress_data * progress_data = fe_data->progress_data;
00249 
00250     if (NULL != progress_data) {
00251         if (NULL != progress_data->progress_box) {
00252             g_warning("removing progress_box");
00253             gtk_container_remove(GTK_CONTAINER(fe_data->target_box),
00254                                  progress_data->progress_box);
00255         }
00256         if (NULL != progress_data->cancel_button) {
00257             g_warning("removing cancel_button");
00258             gtk_container_remove(GTK_CONTAINER(fe_data->target_box),
00259                                  progress_data->cancel_button);
00260         }
00261     }
00262 }
00263 
00271 static gboolean handle_cancel_key(GtkWidget * widget, GdkEventKey * key,
00272                                        struct frontend * fe)
00273 {
00274     if (GDK_Escape == key->keyval) {
00275         fe_gtk_set_answer_goback(fe);
00276         return TRUE;
00277     }
00278     return FALSE;
00279 }
00280 
00286 static void create_cancel_button(struct progress_data * progress_data)
00287 {
00288     struct frontend * fe = progress_data->fe;
00289     GtkWidget * button;
00290     char * label;
00291 
00292     /* XXX: check NULL! */
00293     label = fe_gtk_get_text(fe, "debconf/button-cancel", "Cancel");
00294     button = gtk_button_new_with_label(label);
00295     g_free(label);
00296 
00297     g_signal_connect(G_OBJECT(button), "clicked",
00298                      G_CALLBACK(fe_gtk_set_answer_goback), fe);
00299     fe_gtk_add_global_key_handler(fe, button, G_CALLBACK(handle_cancel_key));
00300     fe_gtk_add_button(fe, button);
00301 
00302     g_object_ref(G_OBJECT(button));
00303     progress_data->cancel_button = button;
00304 }
00305 
00310 static void destroy_cancel_button(struct progress_data * progress_data)
00311 {
00312     GtkWidget * cancel_button = progress_data->cancel_button;
00313 
00314     if (NULL != cancel_button) {
00315         progress_data->cancel_button = NULL;
00316         g_object_unref(G_OBJECT(cancel_button));
00317         gtk_widget_destroy(cancel_button);
00318     }
00319 }
00320 
00326 bool fe_gtk_can_cancel_progress(struct frontend * fe)
00327 {
00328     return DCF_CAPB_PROGRESSCANCEL ==
00329                (fe->capability & DCF_CAPB_PROGRESSCANCEL);
00330 }
00331 
00339 static gboolean init_progress(struct frontend * fe)
00340 {
00341     struct frontend_data * fe_data = fe->data;
00342     struct progress_data * progress_data;
00343 
00344     g_assert(NULL == fe_data->progress_data);
00345 
00346     if (NULL == (progress_data = g_malloc0(sizeof (struct progress_data)))) {
00347         g_warning("g_malloc0 failed.");
00348         return FALSE;
00349     }
00350     progress_data->fe = fe;
00351     create_progress_box(progress_data);
00352     if (CAN_CANCEL_PROGRESS(fe)) {
00353         create_cancel_button(progress_data);
00354     }
00355     fe_data->progress_data = progress_data;
00356 
00357     return TRUE;
00358 }
00359 
00364 static void destroy_progress(struct frontend * fe)
00365 {
00366     struct frontend_data * fe_data = fe->data;
00367     struct progress_data * progress_data = fe_data->progress_data;
00368 
00369     if (NULL == progress_data) {
00370         return;
00371     }
00372     fe_data->progress_data = NULL;
00373     destroy_cancel_button(progress_data);
00374     destroy_progress_box(progress_data);
00375     g_free(progress_data);
00376 }
00377 
00385 static void update_progress_bar(struct frontend * fe, gdouble fraction)
00386 {
00387     struct frontend_data * fe_data = fe->data;
00388     GtkWidget * progress_bar = fe_data->progress_data->progress_bar;
00389 
00390     g_assert(NULL != progress_bar);
00391 
00392     gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress_bar),
00393                               fe->progress_title);
00394     gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress_bar),
00395                                   fraction /* empty progress bar */);
00396 }
00397 
00405 void fe_gtk_progress_start(struct frontend * fe, int min, int max,
00406                            const char * title)
00407 {
00408     struct frontend_data * fe_data = fe->data;
00409 
00410     if (NULL != fe_data->setters) {
00411         /* called out of order */
00412         return;
00413     }
00414     if (NULL != fe_data->progress_data) {
00415         /* nested progress bar... let's clean up first */
00416         fe_gtk_progress_stop(fe);
00417     }
00418     fe_gtk_set_answer(fe, DC_NO_ANSWER);
00419 
00420     gdk_threads_enter();
00421 
00422 #ifdef DI_UDEB
00423     fe_gtk_di_run_dialog(fe);
00424 #endif /* DI_UDEB */
00425 
00426     init_progress(fe);
00427 
00428     g_free(fe->progress_title);
00429     fe->progress_title = g_strdup(title);
00430 
00431     update_progress_bar(fe, 0.0 /* empty */);
00432 
00433     /* XXX: I feel strange to have to set these fields here...
00434      *      Should them be moved elsewhere? And API of this handler
00435      *      changed accordingly? */
00436     fe->progress_min = min;
00437     fe->progress_max = max;
00438     fe->progress_cur = min;
00439     
00440     /* XXX: rename progress_box */
00441     fe_gtk_show_progress(fe);
00442     
00443     gdk_threads_leave();
00444 }
00445 
00453 int fe_gtk_progress_set(struct frontend * fe, int val)
00454 {
00455     struct frontend_data * fe_data = fe->data;
00456     gdouble progress;
00457 
00458     /* XXX: should this kind of sanity checks be in the frontend? */
00459     if (fe->progress_max < val || fe->progress_min > val) {
00460         return DC_NOTOK;
00461     }
00462     if (NULL == fe_data->progress_data) {
00463         /* called out of order */
00464         return DC_NOTOK;
00465     }
00466 
00467     gdk_threads_enter();
00468     fe->progress_cur = val;
00469     if ((fe->progress_max - fe->progress_min) > 0) {
00470         progress = (gdouble) (fe->progress_cur - fe->progress_min) /
00471                    (gdouble) (fe->progress_max - fe->progress_min);
00472         update_progress_bar(fe, progress);
00473     }
00474     fe_gtk_show_progress(fe);
00475     gdk_threads_leave();
00476 
00477     return fe_data->answer;
00478 }
00479 
00488 int fe_gtk_progress_info(struct frontend * fe, const char * info)
00489 {
00490     struct frontend_data * fe_data = fe->data;
00491     struct progress_data * progress_data = fe_data->progress_data;
00492     char * label;
00493 
00494     if (NULL == progress_data) {
00495         /* called out of order */
00496         return DC_NOTOK;
00497     }
00498 
00499     gdk_threads_enter();
00500     label = g_strdup_printf("<i> %s</i>", info);
00501     gtk_label_set_markup(GTK_LABEL(progress_data->progress_label), label);
00502     g_free(label);
00503     gdk_threads_leave();
00504 
00505     if (DC_NO_ANSWER == fe_data->answer) {
00506         return DC_OK;
00507     }
00508     return fe_data->answer;
00509 }
00510 
00517 void fe_gtk_progress_stop(struct frontend * fe)
00518 {
00519     struct frontend_data * fe_data = fe->data;
00520     struct progress_data * progress_data = fe_data->progress_data;
00521 
00522     if (NULL == progress_data) {
00523         /* called out of order */
00524         return;
00525     }
00526 
00527     gdk_threads_enter();
00528     destroy_progress(fe);
00529     gdk_threads_leave();
00530 }
00531 
00532 /* vim: et sw=4 si
00533  */

Generated on Sat Jul 7 23:41:41 2007 for fe_gtk by  doxygen 1.5.1