/* -*- mode: c; style: linux -*- */ /* rollback-capplet-dialog.c * Copyright (C) 2000 Helix Code, Inc. * * Written by Bradford Hovinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include "rollback-capplet-dialog.h" static const gchar date_mod_units[] = { 'y', 'M', 'M', 'd', 'd', 'd', 'h', 'm', 'm', 'm', 'm', '\0' }; static const gint date_mod_values[] = { -1, -6, -1, -7, -3, -1, -1, -30, -10, -5, -1, 0 }; static const gchar *labels[] = { N_("1 year ago"), N_("6 months ago"), N_("1 month ago"), N_("1 week ago"), N_("3 days ago"), N_("1 day ago"), N_("1 hour ago"), N_("30 minutes ago"), N_("10 minutes ago"), N_("5 minutes ago"), N_("1 minute ago"), N_("Current time") }; #define NUM_ROLLBACK_LEVELS (sizeof (labels) / sizeof (const gchar *)) enum { ARG_0, ARG_CAPPLET_NAME }; struct _RollbackCappletDialogPrivate { GladeXML *data; GtkWidget *contents; GtkWidget *control_socket; GtkWidget *label; gchar *capplet_name; gchar *capplet_moniker_name; Bonobo_PropertyControl property_control; Bonobo_PropertyBag control_pb; guint rollback_level; struct tm mod_dates[NUM_ROLLBACK_LEVELS - 1]; }; static GnomeDialogClass *parent_class; static void rollback_capplet_dialog_init (RollbackCappletDialog *rollback_capplet_dialog); static void rollback_capplet_dialog_class_init (RollbackCappletDialogClass *class); static void rollback_capplet_dialog_set_arg (GtkObject *object, GtkArg *arg, guint arg_id); static void rollback_capplet_dialog_get_arg (GtkObject *object, GtkArg *arg, guint arg_id); static void rollback_capplet_dialog_destroy (GtkObject *object); static void rollback_capplet_dialog_finalize (GtkObject *object); static gchar *get_moniker (gchar *capplet_name, struct tm *date); static void get_modified_date (guint rollback_level, struct tm *date); static gboolean do_setup (RollbackCappletDialog *dialog); static void apply_settings (RollbackCappletDialog *dialog); static gboolean is_leap_year (guint year); static void mod_date_by_str (struct tm *date, gint value, gchar unit); static void rollback_changed_cb (RollbackCappletDialog *dialog, GtkAdjustment *adj); static void apply_cb (GtkButton *button, RollbackCappletDialog *dialog); static void close_cb (GtkButton *button, RollbackCappletDialog *dialog); GType rollback_capplet_dialog_get_type (void) { static GType rollback_capplet_dialog_type = 0; if (!rollback_capplet_dialog_type) { GtkTypeInfo rollback_capplet_dialog_info = { "RollbackCappletDialog", sizeof (RollbackCappletDialog), sizeof (RollbackCappletDialogClass), (GtkClassInitFunc) rollback_capplet_dialog_class_init, (GtkObjectInitFunc) rollback_capplet_dialog_init, (GtkArgSetFunc) NULL, (GtkArgGetFunc) NULL }; rollback_capplet_dialog_type = gtk_type_unique (gnome_dialog_get_type (), &rollback_capplet_dialog_info); } return rollback_capplet_dialog_type; } static void rollback_capplet_dialog_init (RollbackCappletDialog *dialog) { GtkAdjustment *adj; GtkWidget *range; GladeXML *data; static const gchar *buttons[] = { GNOME_STOCK_BUTTON_APPLY, GNOME_STOCK_BUTTON_CLOSE, NULL }; data = glade_xml_new (GNOMECC_GLADE_DIR "/rollback.glade", "rollback_dialog"); if (data == NULL) { g_critical ("Your Glade file is either missing or corrupt."); dialog->p = (gpointer) 0xdeadbeef; return; } dialog->p = g_new0 (RollbackCappletDialogPrivate, 1); dialog->p->data = data; dialog->p->contents = glade_xml_get_widget (dialog->p->data, "rollback_dialog"); dialog->p->control_socket = glade_xml_get_widget (dialog->p->data, "control_socket"); dialog->p->label = glade_xml_get_widget (dialog->p->data, "rollback_level_label"); dialog->p->rollback_level = 12; range = glade_xml_get_widget (dialog->p->data, "rollback_scale"); adj = GTK_ADJUSTMENT (gtk_adjustment_new (12, 0, 12, 1, 1, 1)); gtk_range_set_adjustment (GTK_RANGE (range), adj); gtk_signal_connect_object (GTK_OBJECT (adj), "value-changed", GTK_SIGNAL_FUNC (rollback_changed_cb), GTK_OBJECT (dialog)); gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox), dialog->p->contents, TRUE, TRUE, 0); gnome_dialog_constructv (GNOME_DIALOG (dialog), _("Rollback"), buttons); gnome_dialog_button_connect (GNOME_DIALOG (dialog), 0, GTK_SIGNAL_FUNC (apply_cb), dialog); gnome_dialog_button_connect (GNOME_DIALOG (dialog), 1, GTK_SIGNAL_FUNC (close_cb), dialog); } static void rollback_capplet_dialog_class_init (RollbackCappletDialogClass *class) { GtkObjectClass *object_class; gtk_object_add_arg_type ("RollbackCappletDialog::capplet-name", GTK_TYPE_POINTER, GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT_ONLY, ARG_CAPPLET_NAME); object_class = GTK_OBJECT_CLASS (class); object_class->destroy = rollback_capplet_dialog_destroy; object_class->finalize = rollback_capplet_dialog_finalize; object_class->set_arg = rollback_capplet_dialog_set_arg; object_class->get_arg = rollback_capplet_dialog_get_arg; parent_class = GNOME_DIALOG_CLASS (gtk_type_class (gnome_dialog_get_type ())); } static void rollback_capplet_dialog_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) { RollbackCappletDialog *dialog; gchar *tmp; g_return_if_fail (object != NULL); g_return_if_fail (IS_ROLLBACK_CAPPLET_DIALOG (object)); dialog = ROLLBACK_CAPPLET_DIALOG (object); if (dialog->p == (gpointer) 0xdeadbeef) return; switch (arg_id) { case ARG_CAPPLET_NAME: g_return_if_fail (GTK_VALUE_POINTER (*arg) != NULL); dialog->p->capplet_name = GTK_VALUE_POINTER (*arg); dialog->p->capplet_moniker_name = g_strdup (dialog->p->capplet_name); if ((tmp = strstr (dialog->p->capplet_moniker_name, "-capplet")) != NULL) *tmp = '\0'; break; default: g_warning ("Bad argument set"); break; } } static void rollback_capplet_dialog_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) { RollbackCappletDialog *dialog; g_return_if_fail (object != NULL); g_return_if_fail (IS_ROLLBACK_CAPPLET_DIALOG (object)); dialog = ROLLBACK_CAPPLET_DIALOG (object); switch (arg_id) { case ARG_CAPPLET_NAME: GTK_VALUE_POINTER (*arg) = dialog->p->capplet_name; break; default: g_warning ("Bad argument get"); break; } } static void rollback_capplet_dialog_destroy (GtkObject *object) { RollbackCappletDialog *dialog; g_return_if_fail (object != NULL); g_return_if_fail (IS_ROLLBACK_CAPPLET_DIALOG (object)); dialog = ROLLBACK_CAPPLET_DIALOG (object); if (dialog->p != (gpointer) 0xdeadbeef) { bonobo_object_release_unref (dialog->p->property_control, NULL); bonobo_object_release_unref (dialog->p->control_pb, NULL); gtk_object_destroy (GTK_OBJECT (dialog->p->data)); } if (dialog->p->capplet_name != NULL) { g_free (dialog->p->capplet_name); dialog->p->capplet_name = NULL; } if (dialog->p->capplet_moniker_name != NULL) { g_free (dialog->p->capplet_moniker_name); dialog->p->capplet_moniker_name = NULL; } GTK_OBJECT_CLASS (parent_class)->destroy (object); } static void rollback_capplet_dialog_finalize (GtkObject *object) { RollbackCappletDialog *dialog; g_return_if_fail (object != NULL); g_return_if_fail (IS_ROLLBACK_CAPPLET_DIALOG (object)); dialog = ROLLBACK_CAPPLET_DIALOG (object); if (dialog->p != (gpointer) 0xdeadbeef) g_free (dialog->p); GTK_OBJECT_CLASS (parent_class)->finalize (object); } GtkObject * rollback_capplet_dialog_new (gchar *capplet_name) { GtkObject *object; object = gtk_object_new (rollback_capplet_dialog_get_type (), "capplet-name", capplet_name, NULL); if (ROLLBACK_CAPPLET_DIALOG (object)->p == (gpointer) 0xdeadbeef) { gtk_object_destroy (object); return NULL; } if (do_setup (ROLLBACK_CAPPLET_DIALOG (object))) { return object; } else { gtk_object_destroy (object); return NULL; } } static gchar * get_moniker (gchar *capplet_name, struct tm *date) { if (date == NULL) return g_strconcat ("archive:user-archive#archiverdb:", capplet_name, NULL); else return g_strdup_printf ("archive:user-archive#archiverdb:[|%04d%02d%02d%02d%02d%02d]%s", date->tm_year + 1900, date->tm_mon + 1, date->tm_mday, date->tm_hour, date->tm_min, date->tm_sec, capplet_name); } static void get_modified_date (guint rollback_level, struct tm *date) { time_t t; t = time (NULL); gmtime_r (&t, date); mod_date_by_str (date, date_mod_values[rollback_level], date_mod_units[rollback_level]); } /* do_setup * * Sets up the dialog's controls * * Returns TRUE on success and FALSE on failure */ static gboolean do_setup (RollbackCappletDialog *dialog) { CORBA_Environment ev; Bonobo_Control control; BonoboControlFrame *cf; GtkWidget *control_wid; GtkWidget *err_dialog; gchar *tmp, *tmp1; gchar *oaf_iid; gchar *moniker; guint i; CORBA_exception_init (&ev); tmp = g_strdup (dialog->p->capplet_moniker_name); while ((tmp1 = strchr (tmp, '-'))) *tmp1 = '_'; oaf_iid = g_strconcat ("OAFIID:Bonobo_Control_Capplet_", tmp, NULL); dialog->p->property_control = bonobo_get_object (oaf_iid, "IDL:Bonobo/PropertyControl:1.0", &ev); g_free (oaf_iid); g_free (tmp); if (BONOBO_EX (&ev) || dialog->p->property_control == CORBA_OBJECT_NIL) { err_dialog = gnome_error_dialog ("Could not load the capplet."); gnome_dialog_run_and_close (GNOME_DIALOG (err_dialog)); return FALSE; } control = Bonobo_PropertyControl_getControl (dialog->p->property_control, 0, &ev); if (BONOBO_EX (&ev) || control == CORBA_OBJECT_NIL) { bonobo_object_release_unref (dialog->p->property_control, NULL); return FALSE; } control_wid = bonobo_widget_new_control_from_objref (control, CORBA_OBJECT_NIL); if (control_wid == NULL) { bonobo_object_release_unref (dialog->p->property_control, NULL); bonobo_object_release_unref (control, NULL); return FALSE; } for (i = 0; i < NUM_ROLLBACK_LEVELS - 1; i++) get_modified_date (i, &(dialog->p->mod_dates[i])); moniker = get_moniker (dialog->p->capplet_moniker_name, NULL); cf = bonobo_widget_get_control_frame (BONOBO_WIDGET (control_wid)); dialog->p->control_pb = bonobo_control_frame_get_control_property_bag (cf, &ev); bonobo_property_bag_client_set_value_string (dialog->p->control_pb, "moniker", moniker, &ev); g_free (moniker); if (BONOBO_EX (&ev)) { err_dialog = gnome_error_dialog ("Could not load your configuration settings."); gnome_dialog_run_and_close (GNOME_DIALOG (err_dialog)); bonobo_object_release_unref (dialog->p->property_control, NULL); bonobo_object_release_unref (dialog->p->control_pb, NULL); gtk_object_destroy (GTK_OBJECT (control_wid)); return FALSE; } /* gtk_widget_set_sensitive (control_wid, FALSE); */ gtk_container_add (GTK_CONTAINER (dialog->p->control_socket), control_wid); gtk_widget_show_all (dialog->p->contents); CORBA_exception_free (&ev); return TRUE; } static void apply_settings (RollbackCappletDialog *dialog) { ConfigArchiver_Archive archive; ConfigArchiver_Location location; CORBA_Environment ev; xmlDocPtr doc; if (dialog->p->rollback_level == NUM_ROLLBACK_LEVELS - 1) return; CORBA_exception_init (&ev); archive = bonobo_get_object ("archive:user-archive", "IDL:ConfigArchiver/Archive:1.0", &ev); if (BONOBO_EX (&ev) || archive == CORBA_OBJECT_NIL) { g_critical ("Could not retrieve archive (%s)", ev._repo_id); CORBA_exception_free (&ev); return; } location = ConfigArchiver_Archive__get_currentLocation (archive, &ev); if (BONOBO_EX (&ev) || location == CORBA_OBJECT_NIL) { g_critical ("Could not retrieve current location (%s)", ev._repo_id); bonobo_object_release_unref (archive, NULL); CORBA_exception_free (&ev); return; } doc = location_client_load_rollback_data (location, &(dialog->p->mod_dates[dialog->p->rollback_level]), 0, dialog->p->capplet_moniker_name, TRUE, &ev); if (BONOBO_EX (&ev) || doc == NULL) { gchar *filename; filename = g_strconcat (GNOMECC_DEFAULTS_DIR "/", dialog->p->capplet_moniker_name, ".xml", NULL); doc = xmlParseFile (filename); g_free (filename); if (doc == NULL) { g_critical ("Could not load rollback data (%s)", ev._repo_id); bonobo_object_release_unref (location, NULL); bonobo_object_release_unref (archive, NULL); CORBA_exception_free (&ev); return; } CORBA_exception_init (&ev); } location_client_store_xml (location, dialog->p->capplet_moniker_name, doc, ConfigArchiver_STORE_MASK_PREVIOUS, &ev); if (BONOBO_EX (&ev) || doc == NULL) g_critical ("Could not store rollback data (%s)", ev._repo_id); xmlFreeDoc (doc); bonobo_object_release_unref (archive, NULL); bonobo_object_release_unref (location, NULL); CORBA_exception_free (&ev); } static gboolean is_leap_year (guint year) { if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) return TRUE; else return FALSE; } /* mod_date_by_str * * Modify the given date structure using the given time differential string * encoding */ static void mod_date_by_str (struct tm *date, gint value, gchar unit) { static const guint month_days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; switch (unit) { case 'm': date->tm_min += value; break; case 'h': date->tm_hour += value; break; case 'd': date->tm_mday += value; break; case 'M': date->tm_mon += value; break; case 'y': date->tm_year += value; break; } if (date->tm_min < 0) { date->tm_min = 59; date->tm_hour--; } if (date->tm_hour < 0) { date->tm_hour = 23; date->tm_mday--; } if (date->tm_mday < 1) { if (date->tm_mon == 2 && is_leap_year (date->tm_year)) date->tm_mday = 29; else date->tm_mday = month_days[(date->tm_mon + 11) % 12]; date->tm_mon--; } if (date->tm_mon < 0) { date->tm_mon = 11; date->tm_year--; } } static void rollback_changed_cb (RollbackCappletDialog *dialog, GtkAdjustment *adj) { gchar *moniker; CORBA_Environment ev; CORBA_exception_init (&ev); dialog->p->rollback_level = adj->value; gtk_label_set_text (GTK_LABEL (dialog->p->label), labels[dialog->p->rollback_level]); if (dialog->p->rollback_level == NUM_ROLLBACK_LEVELS - 1) moniker = get_moniker (dialog->p->capplet_moniker_name, NULL); else moniker = get_moniker (dialog->p->capplet_moniker_name, &(dialog->p->mod_dates[dialog->p->rollback_level])); bonobo_property_bag_client_set_value_string (dialog->p->control_pb, "moniker", moniker, &ev); g_free (moniker); if (BONOBO_EX (&ev)) { g_critical ("Could not load settings for rollback level %.0f (%s)", adj->value, ev._repo_id); if (adj->value != dialog->p->rollback_level) gtk_adjustment_set_value (adj, dialog->p->rollback_level); } else { dialog->p->rollback_level = adj->value; } CORBA_exception_free (&ev); } static void apply_cb (GtkButton *button, RollbackCappletDialog *dialog) { apply_settings (dialog); } static void close_cb (GtkButton *button, RollbackCappletDialog *dialog) { gnome_dialog_close (GNOME_DIALOG (dialog)); }