aboutsummaryrefslogblamecommitdiffstats
path: root/calendar/gui/e-meeting-edit.c
blob: 6ae266174d87155826c50f013b754d6050e42e60 (plain) (tree)
























                                                                            
                 



                                                    
 







                                                            





                                   










                                                             


                                                                        










                                   
 























                                                                                  





                                    
                                    
                    

                                                                        
 




                                                                             






                                                                                                        











                                                                                          







                                                                                                      
                                                                   







                                     

                                    

                                                                        



                         






                                                                     
 






                                     
                                    
 



















                                                                        






                                                                          













                                                                  


















































                                                                                                 

                                                                        



                                                                                    

                                                                                        

                                                                                
                                                                                  

























                                                                                  
         








                                                                  
 


                                                                           
 
                                            
 
                                                                         

                              

                                                                                
 
                                                                


                                                     




                                                                          













                                                                                                 

                                                         






















                                                                                                      










                                                                        
                                                                                
                                                                
 


                                                                    
                                   
         


                                         




                                                           




                                                                        


                                                                                              
                                                                                           


                                                        











                                                                                               





                                                         





                                                                        


                                                                                            
                                                                                           



                                                        


                                                 
                

                                                                                               
 
                                        
 
                                                         
 




                                                                                              
 

                                                                                  




                                                                                                    
                                                                                      
 








                                                                                                                    
                        
                                                                              
                                           
 

                                             




         





                                           
 




                                                                        
 












                                                                                            

























                                                                          
 






                                      
 

        

     
                                       
 
                                    
                                                            
                           

                         


                                          
 
                                                     
 



                                                                                     
        

                                                                                   

                                                                          
 


                                                                                                             
 

                                                                              
 

                                                                                    
 

                                                                               
 

                                                                           
 


                                                                          

                                                               
                                                                             

                                                                  
                                                                                

                                                                

                                                                              

                                                                                    






                                                                                                       





                                                                                        














                                                                                     




                                                                                                      





                                                                                            
                                                        

         
 
                                               


                    

                                                          
 

                                                       
 
                                                  
 
/* Evolution calendar - Meeting editor dialog
 *
 * Copyright (C) 2000 Helix Code, Inc.
 *
 * Authors: Jesse Pavel <jpavel@helixcode.com>
 *
 * 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 of the License, 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.
 */

#include <config.h>
#include <gnome.h>
#include <glade/glade.h>
#include <icaltypes.h>
#include <ical.h>
#include "e-meeting-edit.h"

#define E_MEETING_GLADE_XML "e-meeting-dialog.glade"


typedef struct _EMeetingEditorPrivate EMeetingEditorPrivate;

struct _EMeetingEditorPrivate {
    /* These are the widgets to be used in the GUI. */
    GladeXML *xml;
    GtkWidget *meeting_window;
    GtkWidget *attendee_list;
    GtkWidget *address_entry;
    GtkWidget *edit_dialog;
    GtkWidget *organizer_entry;
    GtkWidget *role_entry;
    GtkWidget *rsvp_check;
    
    gint changed_signal_id;

    /* Various pieces of information. */
    gint selected_row;
    CalComponent *comp;
    CalClient *client;
    icalcomponent *icalcomp, *vevent;

    gint numentries;  /* How many attendees are there? */
    gboolean dirty;  /* Has anything changed? */
}; 

#define NUM_COLUMNS 4  /* The number of columns in our attendee list. */

enum column_names {ADDRESS_COL, ROLE_COL, RSVP_COL, STATUS_COL};

static gchar *partstat_values[] = {
    "Needs action",
    "Accepted",
    "Declined",
    "Tentative",
    "Delegated",
    "Completed",
    "In Progress",
    "Unknown"
};

static gchar *role_values[] = {
    "Chair",
    "Required Participant",
    "Optional Participant",
    "Non-Participant",
    "Other"
};


/* Note that I have to iterate and check myself because
   ical_property_get_xxx_parameter doesn't take into account the
   kind of parameter for which you wish to search! */
static icalparameter *
get_icalparam_by_type (icalproperty *prop, icalparameter_kind kind)
{
    icalparameter *param;

    for (param = icalproperty_get_first_parameter (prop, ICAL_ANY_PARAMETER);
         param != NULL && icalparameter_isa (param) != kind;
         param = icalproperty_get_next_parameter (prop, ICAL_ANY_PARAMETER) );

    return param;
}


static gboolean
window_delete_cb (GtkWidget *widget,
          GdkEvent *event,
          gpointer data)
{   
    EMeetingEditorPrivate *priv;
    gchar *text;

    priv = (EMeetingEditorPrivate *) ((EMeetingEditor *)data)->priv;

    if (priv->dirty == TRUE) {
        /* FIXME: notify the event editor that our data has changed. 
            For now, I'll just display a dialog box. */
        {
            GtkWidget *dialog;
            icalproperty *prop;
            icalvalue *value;

            /* Save the organizer into the iCAL object. */
                prop = icalcomponent_get_first_property (priv->vevent, ICAL_ORGANIZER_PROPERTY);

            text = gtk_entry_get_text (GTK_ENTRY (priv->organizer_entry));
            if (strlen (text) > 0) {
                gchar buffer[200];
                g_snprintf (buffer, 190, "MAILTO:%s", text);
                
                if (prop == NULL) {
                    /* We need to add an ORGANIZER property. */
                    prop = icalproperty_new (ICAL_ORGANIZER_PROPERTY);
                    icalcomponent_add_property (priv->vevent, prop);
                }
                value = icalvalue_new_text (buffer);
                icalproperty_set_value (prop, value);
            }
        
            dialog = gnome_warning_dialog_parented ("Note that the meeting has changed,\n"
                                "and you should save this event.",
                                GTK_WINDOW (priv->meeting_window));
            gnome_dialog_run (GNOME_DIALOG(dialog));
        }
    }

    gtk_entry_set_text (GTK_ENTRY (priv->organizer_entry), "");

    return (FALSE);
}

static void 
window_destroy_cb (GtkWidget *widget,
           gpointer data)
{
    EMeetingEditorPrivate *priv;

    priv = (EMeetingEditorPrivate *) ((EMeetingEditor *)data)->priv;

    gtk_main_quit ();
    return;
}

/* put_property_in_list() synchronizes the display of row `rownum'
   in our attendee list to the values of `prop'. If rownum < 0,
   then put_property_in_list() will append a new row. 
   If the property doesn't contain certain parameters that we deem
   necessary, it will add them. */
static void
put_property_in_list (icalproperty *prop, gint rownum, gpointer data)
{
    gchar *row_text[NUM_COLUMNS];
    gchar *text, *new_text;
    icalparameter *param;
    icalvalue *value;
    gint enumval;
    gint cntr;

    EMeetingEditorPrivate *priv;

    priv = (EMeetingEditorPrivate *) ((EMeetingEditor *)data)->priv;
    
    value = icalproperty_get_value (prop);

    if (value != NULL) {
        text = strdup (icalvalue_as_ical_string (value));
    
        /* Here I strip off the "MAILTO:" if it is present. */
        new_text = strchr (text, ':');
        if (new_text != NULL)
            new_text++;
        else
            new_text = text;
    
        row_text[ADDRESS_COL] = g_strdup (new_text);
        g_free (text);
    }

    param = get_icalparam_by_type (prop, ICAL_ROLE_PARAMETER);
    if (param == NULL) {
        param = icalparameter_new_role (ICAL_ROLE_REQPARTICIPANT);
        icalproperty_add_parameter (prop, param);
    }
        
    enumval = icalparameter_get_role (param);
    if (enumval < 0 || enumval > 4)
        enumval = 4;
    
    row_text[ROLE_COL] = role_values [enumval];

    param = get_icalparam_by_type (prop, ICAL_RSVP_PARAMETER);
    if (param == NULL) {
        param = icalparameter_new_rsvp (TRUE);
        icalproperty_add_parameter (prop, param);
    }

    if (icalparameter_get_rsvp (param))
        row_text[RSVP_COL] = "Y";
    else
        row_text[RSVP_COL] = "N";

    param = get_icalparam_by_type (prop, ICAL_PARTSTAT_PARAMETER);
    if (param == NULL) {
        param = icalparameter_new_partstat (ICAL_PARTSTAT_NEEDSACTION);
        icalproperty_add_parameter (prop, param);
    }

    enumval = icalparameter_get_partstat (param);
    if (enumval < 0 || enumval > 7) {
        enumval = 7;
    }

    row_text[STATUS_COL] = partstat_values [enumval];

    if (rownum < 0) {
        gtk_clist_append (GTK_CLIST (priv->attendee_list), row_text);
        gtk_clist_set_row_data (GTK_CLIST (priv->attendee_list), priv->numentries, prop);
        priv->numentries++;
    }
    else {
        for (cntr = 0; cntr < NUM_COLUMNS; cntr++) {
            gtk_clist_set_text (GTK_CLIST (priv->attendee_list), 
                        rownum,
                        cntr,
                        row_text[cntr]);
        }
    }

    g_free (row_text[ADDRESS_COL]);
}

    

/* edit_attendee() performs the GUI manipulation and interaction for
   editing `prop' and returns TRUE if the user indicated that he wants
   to save the new property information.

   Note that it is necessary that the property have parameters of the types
   RSVP, PARTSTAT, and ROLE already when passed into this function. */
static gboolean
edit_attendee (icalproperty *prop, gpointer data)
{
    EMeetingEditorPrivate *priv;
    gint button_num;
    gchar *new_text, *text;
    icalparameter *param;
    icalvalue *value;
    gchar buffer[200];
    gint cntr;
    gint enumval;
    gboolean retval;

    priv = (EMeetingEditorPrivate *) ((EMeetingEditor *)data)->priv;

    g_return_val_if_fail (prop != NULL, FALSE);

    if (priv->edit_dialog == NULL || priv->address_entry == NULL) {
        priv->edit_dialog = glade_xml_get_widget (priv->xml, "edit_dialog");
        priv->address_entry = glade_xml_get_widget (priv->xml, "address_entry");

        gnome_dialog_set_close (GNOME_DIALOG (priv->edit_dialog), TRUE);
        gnome_dialog_editable_enters (GNOME_DIALOG (priv->edit_dialog), 
                          GTK_EDITABLE (priv->address_entry));
        gnome_dialog_close_hides (GNOME_DIALOG (priv->edit_dialog), TRUE);
        gnome_dialog_set_default (GNOME_DIALOG (priv->edit_dialog), 0);
    }

    g_return_val_if_fail (priv->edit_dialog != NULL, FALSE);
    g_return_val_if_fail (priv->address_entry != NULL, FALSE);

    gtk_widget_realize (priv->edit_dialog);
    
    value = icalproperty_get_value (prop);

    if (value != NULL) {
        text = strdup (icalvalue_as_ical_string (value));
    
        /* Here I strip off the "MAILTO:" if it is present. */
        new_text = strchr (text, ':');
        if (new_text != NULL)
            new_text++;
        else
            new_text = text;
    
        gtk_entry_set_text (GTK_ENTRY (priv->address_entry), new_text);
        g_free (text);
    }
    else {
        gtk_entry_set_text (GTK_ENTRY (priv->address_entry), "");
    }
                

    param = get_icalparam_by_type (prop, ICAL_ROLE_PARAMETER);
    enumval = icalparameter_get_role (param);
    if (enumval < 0 || enumval > 4)
        enumval = 4;
    
    text = role_values [enumval];
    gtk_entry_set_text (GTK_ENTRY (priv->role_entry), text);

    param = get_icalparam_by_type (prop, ICAL_RSVP_PARAMETER);
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->rsvp_check),
                    icalparameter_get_rsvp (param));

    gtk_widget_show (priv->edit_dialog);

    button_num = gnome_dialog_run (GNOME_DIALOG (priv->edit_dialog));

    if (button_num == 0) {
        /* The user pressed the OK button. */
        new_text = gtk_entry_get_text (GTK_ENTRY (priv->address_entry));

        g_snprintf (buffer, 190, "MAILTO:%s", new_text);
        value = icalvalue_new_text (buffer);
        icalproperty_set_value (prop, value);

        /* Take care of the ROLE. */
        icalproperty_remove_parameter (prop, ICAL_ROLE_PARAMETER);

        param = NULL;
        text = gtk_entry_get_text (GTK_ENTRY(priv->role_entry));

        for (cntr = 0; cntr < 5; cntr++) {
            if (strncmp (text, role_values[cntr], 3) == 0) {
                param = icalparameter_new_role (cntr);
                break;
            }
        }

        if (param == NULL) {
            g_print ("e-meeting-edit.c: edit_attendee() the ROLE param was null.\n");
            /* Use this as a default case, if none of the others match. */
            param = icalparameter_new_role (ICAL_ROLE_REQPARTICIPANT);
        }

        icalproperty_add_parameter (prop, param);

        /* Now the RSVP. */
        icalproperty_remove_parameter (prop, ICAL_RSVP_PARAMETER);

        param = icalparameter_new_rsvp 
                (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->rsvp_check)));
        icalproperty_add_parameter (prop, param);

        retval = TRUE;
    }
    else  /* The user didn't say OK. */
        retval = FALSE;
    
    return retval;
}


static void 
add_button_clicked_cb (GtkWidget *widget, gpointer data)
{
    EMeetingEditorPrivate *priv;
    icalproperty *prop;
    icalparameter *param;

    priv = (EMeetingEditorPrivate *) ((EMeetingEditor *)data)->priv;

    prop = icalproperty_new (ICAL_ATTENDEE_PROPERTY);
    param = icalparameter_new_role (ICAL_ROLE_REQPARTICIPANT); 
    icalproperty_add_parameter (prop, param);
    param = icalparameter_new_rsvp (TRUE); 
    icalproperty_add_parameter (prop, param);
    param = icalparameter_new_partstat (ICAL_PARTSTAT_NEEDSACTION);
    icalproperty_add_parameter (prop, param);

    if (edit_attendee (prop, data) == TRUE) {
        /* Let's add this property to our component and to the CList. */
        icalcomponent_add_property (priv->vevent, prop);

        /* The -1 indicates that we should add a new row. */
        put_property_in_list (prop, -1, data);

        priv->dirty = TRUE;
    }
    else {
        icalproperty_free (prop);
    }
}   

static void 
delete_button_clicked_cb (GtkWidget *widget, gpointer data)
{
    EMeetingEditorPrivate *priv;

    priv = (EMeetingEditorPrivate *) ((EMeetingEditor *)data)->priv;

    if (priv->selected_row < 0) {
        GtkWidget *dialog;

        dialog = gnome_warning_dialog_parented ("You must select an entry to delete.",
                            GTK_WINDOW (priv->meeting_window));
        gnome_dialog_run (GNOME_DIALOG(dialog));
    }
    else {
        /* Delete the associated property from the iCAL object. */
        icalproperty *prop;

        prop = (icalproperty *)gtk_clist_get_row_data (GTK_CLIST (priv->attendee_list),
                                   priv->selected_row);
        icalcomponent_remove_property (priv->vevent, prop);
        icalproperty_free (prop);

        gtk_clist_remove (GTK_CLIST (priv->attendee_list), priv->selected_row);
        priv->selected_row = -1;
        priv->numentries--;
        priv->dirty = TRUE;
    }
}

static void 
edit_button_clicked_cb (GtkWidget *widget, gpointer data)
{
    EMeetingEditorPrivate *priv;

    priv = (EMeetingEditorPrivate *) ((EMeetingEditor *)data)->priv;

    
    if (priv->selected_row < 0) {
        GtkWidget *dialog;

        dialog = gnome_warning_dialog_parented ("You must select an entry to edit.",
                            GTK_WINDOW (priv->meeting_window));
        gnome_dialog_run (GNOME_DIALOG(dialog));
        return;
    }
    else {
        icalproperty *prop, *new_prop;
        icalparameter *param, *new_param;
        icalvalue *value, *new_value;
        
        prop = (icalproperty *)gtk_clist_get_row_data (GTK_CLIST (priv->attendee_list),
                                   priv->selected_row);

        g_assert (prop != NULL);

        new_prop = icalproperty_new_clone (prop);

        if (edit_attendee (new_prop, data)) {
            /* The user hit Okay. */
            /*We need to synchronize the old property with the newly edited one.*/
            value = icalvalue_new_clone (icalproperty_get_value (new_prop));
            icalproperty_set_value (prop, value);

            icalproperty_remove_parameter (prop, ICAL_ROLE_PARAMETER);
            icalproperty_remove_parameter (prop, ICAL_RSVP_PARAMETER);

            param = get_icalparam_by_type (prop, ICAL_ROLE_PARAMETER);
            if (param != NULL)
                g_print ("e-meeting-edit.c: param should be NULL, but it isn't.\n");

            icalproperty_remove_parameter (prop, ICAL_PARTSTAT_PARAMETER);

            param = icalparameter_new_clone (get_icalparam_by_type (new_prop, ICAL_ROLE_PARAMETER));
            g_assert (param != NULL);
            icalproperty_add_parameter (prop, param);
            param = icalparameter_new_clone (get_icalparam_by_type (new_prop, ICAL_RSVP_PARAMETER));
            g_assert (param != NULL);
            icalproperty_add_parameter (prop, param);
            param = icalparameter_new_clone (get_icalparam_by_type (new_prop, ICAL_PARTSTAT_PARAMETER));
            g_assert (param != NULL);
            icalproperty_add_parameter (prop, param);
            
            put_property_in_list (prop, priv->selected_row, data);
            priv->dirty = TRUE;

        }
        icalproperty_free (new_prop);
    }
}



static void 
list_row_select_cb  (GtkWidget *widget,
                     gint row,
                     gint column,
                     GdkEventButton *event,
                     gpointer data)
{
    EMeetingEditorPrivate *priv;

    priv = (EMeetingEditorPrivate *) ((EMeetingEditor *)data)->priv;
    
    priv->selected_row = row;
}

static void
organizer_changed_cb (GtkWidget *widget, gpointer data)
{
    EMeetingEditorPrivate *priv;

    priv = (EMeetingEditorPrivate *) ((EMeetingEditor *)data)->priv;

    gtk_signal_disconnect (GTK_OBJECT (priv->organizer_entry), priv->changed_signal_id);

    priv->dirty = TRUE;
}


/* ------------------------------------------------------------ */
/* --------------------- Exported Functions ------------------- */
/* ------------------------------------------------------------ */

EMeetingEditor * 
e_meeting_editor_new (CalComponent *comp, CalClient *client)
{
    EMeetingEditor *object;
    EMeetingEditorPrivate *priv;

    object = (EMeetingEditor *)g_new(EMeetingEditor, 1);
    
    priv = (EMeetingEditorPrivate *) g_new0(EMeetingEditorPrivate, 1);
    priv->selected_row = -1;
    priv->comp = comp;
    priv->client = client;
    priv->icalcomp = cal_component_get_icalcomponent (comp);
    
    object->priv = priv;

    return object;  
}

void
e_meeting_editor_free (EMeetingEditor *editor)
{
    if (editor == NULL)
        return;
        
    if (editor->priv != NULL)
        g_free (editor->priv);
    
    g_free (editor);
}
    


void 
e_meeting_edit (EMeetingEditor *editor)
{
    EMeetingEditorPrivate *priv;
    GtkWidget *add_button, *delete_button, *edit_button;
    icalproperty *prop;
    icalvalue *value;
    gchar *text;


    g_return_if_fail (editor != NULL);

    priv = (EMeetingEditorPrivate *)editor->priv;

    g_return_if_fail (priv != NULL);


    priv->xml = glade_xml_new (EVOLUTION_GLADEDIR "/" E_MEETING_GLADE_XML, NULL);
    
    priv->meeting_window =  glade_xml_get_widget (priv->xml, "meeting_window");
    priv->attendee_list = glade_xml_get_widget (priv->xml, "attendee_list");
    priv->role_entry = glade_xml_get_widget (priv->xml, "role_entry");
    priv->rsvp_check = glade_xml_get_widget (priv->xml, "rsvp_check");

    gtk_clist_set_column_justification (GTK_CLIST (priv->attendee_list), ROLE_COL, GTK_JUSTIFY_CENTER);
    gtk_clist_set_column_justification (GTK_CLIST (priv->attendee_list), RSVP_COL, GTK_JUSTIFY_CENTER);
    gtk_clist_set_column_justification (GTK_CLIST (priv->attendee_list), STATUS_COL, GTK_JUSTIFY_CENTER);

        gtk_signal_connect (GTK_OBJECT (priv->meeting_window), "delete_event",
                            GTK_SIGNAL_FUNC (window_delete_cb), editor);

    gtk_signal_connect_after (GTK_OBJECT (priv->meeting_window), "delete_event",
                  GTK_SIGNAL_FUNC (window_destroy_cb), editor);

        gtk_signal_connect (GTK_OBJECT (priv->meeting_window), "destroy_event",
                            GTK_SIGNAL_FUNC (window_destroy_cb), editor);

    gtk_signal_connect (GTK_OBJECT (priv->attendee_list), "select_row",
                GTK_SIGNAL_FUNC (list_row_select_cb), editor);

    add_button = glade_xml_get_widget (priv->xml, "add_button");
    delete_button = glade_xml_get_widget (priv->xml, "delete_button");
    edit_button = glade_xml_get_widget (priv->xml, "edit_button");

    gtk_signal_connect (GTK_OBJECT (add_button), "clicked",
                GTK_SIGNAL_FUNC (add_button_clicked_cb), editor);
    
    gtk_signal_connect (GTK_OBJECT (delete_button), "clicked",
                GTK_SIGNAL_FUNC (delete_button_clicked_cb), editor);

    gtk_signal_connect (GTK_OBJECT (edit_button), "clicked",
                GTK_SIGNAL_FUNC (edit_button_clicked_cb), editor);

    priv->organizer_entry = glade_xml_get_widget (priv->xml, "organizer_entry");

    if (icalcomponent_isa (priv->icalcomp) != ICAL_VEVENT_COMPONENT)
        priv->vevent = icalcomponent_get_first_component(priv->icalcomp,ICAL_VEVENT_COMPONENT);
    else
        priv->vevent = priv->icalcomp;

    g_assert (priv->vevent != NULL);

    /* Let's extract the organizer, if there is one. */
        prop = icalcomponent_get_first_property (priv->vevent, ICAL_ORGANIZER_PROPERTY);

    if (prop != NULL) {
        gchar *buffer;

            value = icalproperty_get_value (prop);
        buffer = g_strdup (icalvalue_as_ical_string (value));
            if (buffer != NULL) {
            /* Strip off the MAILTO:, if it is present. */
                text = strchr (buffer, ':');
            if (text == NULL)
                text = buffer;
            else
                text++;
                
            gtk_entry_set_text (GTK_ENTRY (priv->organizer_entry), text);
            g_free (buffer);
        }
        
    }

    priv->changed_signal_id = gtk_signal_connect (GTK_OBJECT (priv->organizer_entry), "changed",
                              GTK_SIGNAL_FUNC (organizer_changed_cb), editor);


    /* Let's go through the iCAL object, and create a list entry
       for each ATTENDEE property. */
        for (prop = icalcomponent_get_first_property (priv->vevent, ICAL_ATTENDEE_PROPERTY);
             prop != NULL;
             prop = icalcomponent_get_next_property (priv->vevent, ICAL_ATTENDEE_PROPERTY))
    {
        put_property_in_list (prop, -1, editor);
    }
    

    gtk_widget_show (priv->meeting_window);

    gtk_main ();

    if (priv->meeting_window != NULL)
        gtk_widget_destroy (priv->meeting_window);

    if (priv->edit_dialog != NULL)
        gtk_widget_destroy (priv->edit_dialog);

    gtk_object_unref (GTK_OBJECT (priv->xml));
}