Files
evolution/shell/evolution-activity-client.c
Ettore Perazzoli 4eb4ae3be8 [Implement an Outlook-style "New" dropdown button. It is basically
done but it needs pretty icons so I am leaving it disabled for now.]

* e-combo-button.c: Remove member `separator' from
`EComboButtonPrivate'.  New members `icon', `label'.
(init): There shall be no separator no more.  Init `icon' and
`label' to %NULL.
(e_combo_button_construct): Set no relief.
(e_combo_button_new): Don't get a @menu arg anymore.
(e_combo_button_construct): Likewise.
(e_combo_button_set_icon): New.
(e_combo_button_set_label): New.
(e_combo_button_set_menu): New.
(impl_clicked): New, overriding the "clicked" method for
GtkButton.
(class_init): Install.
(impl_button_release_event): Removed.
(class_init): No need to override ::release_event with this
anymore.
(impl_released): New, override for the GtkButton::released method.
(class_init): Install.

* e-shell-user-creatable-items-handler.c: New member `id' in
struct `Component'.  New member `icon' in struct `MenuItem'.
(component_free): Free ->id.
(component_new): Renamed from `component_new_from_client'.  Get an
@id arg and set ->id accordingly.
(e_shell_user_creatable_items_handler_add_component): New arg @id.
Pass it to `component_new'.
(e_shell_user_creatable_items_handler_setup_menus): New arg
@current_component_id.
(e_shell_user_creatable_items_handler_update_menus): New.
(set_current_component): New helper function.
(get_component_by_id): New helper function.
(add_verbs): Renamed from `add_verbs_to_ui_component()'.  Get a
@shell_view instead of a @ui_component.  Set the SHELL_VIEW_KEY on
the ui_component of the shell_view to point to the shell_view
itself.
(ensure_menu_items): Set item->icon to NULL.
(free_menu_items): Unref item->icon.
(ensure_menu_xml): Set the icon as well.
(get_default_action_for_view): New helper function.
(find_menu_item_for_verb): New helper function.
(shell_view_view_changed_callback): New callback, set up the label
on the "New" button depending on the current component.
(e_shell_user_creatable_items_handler_attach_menus): New.  For
now, do not display the toolbar button yet.
(execute_verb): New helper function, splitting out code from
`verb_fn'.
(verb_fn): Use `execute_verb'.
(combo_button_activate_default_callback): Callback for the
"activate_default" signal on the EComboButton.
(setup_toolbar_button): Connect.

* evolution-shell-component.c: New member `icon' in
`UserCreatableItemType'.
(impl__get_userCreatableItemTypes): Put the ->icon in the
corba_type as well.
(user_creatable_item_type_new): Get a new @icon argument.
(evolution_shell_component_add_user_creatable_item): New arg
@icon.

* Evolution-ShellComponent.idl: New member `icon' in struct
`UserCreatableItemType'.

* evolution-test-component.c (register_component): Pass a NULL
@icon to `evolution_shell_component_add_user_creatable_item()'.

* e-shell-view.c (class_init): Add the signal to the class.
(e_shell_view_display_uri): Emit "view_changed".
(e_shell_view_get_current_component_id): New.

* evolution-shell-component-client.c: New member `id' in
EvolutionShellComponentClientPrivate.
(init): Init to NULL.
(impl_destroy): Free.
(evolution_shell_component_client_new_for_objref): Removed.
(evolution_shell_component_client_construct): New arg @id.
Initialize ->id from it.
(evolution_shell_component_client_get_id): New.

* e-shell-view.h: New signal "view_changed".

* evolution-activity-client.c (create_icon_from_pixbuf): Removed.
(create_corba_animated_icon_from_pixbuf_array): Removed.
(evolution_activity_client_construct): Use
`e_new_corba_animated_icon_from_pixbuf_array()' instead.

svn path=/trunk/; revision=15438
2002-01-23 22:21:24 +00:00

427 lines
12 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/* evolution-activity-client.c
*
* Copyright (C) 2001 Ximian, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* 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.
*
* Author: Ettore Perazzoli <ettore@ximian.com>
*/
/* Another evil GTK+ object wrapper for a CORBA API. In this case, the wrapper
is needed to avoid sending too frequent CORBA requests across the wire, thus
slowing the client down. The wrapper makes sure that there is a minimum
amount of time between each CORBA method invocation. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "evolution-activity-client.h"
#include "e-shell-corba-icon-utils.h"
#include <gtk/gtksignal.h>
#include <gtk/gtkmain.h>
#include <bonobo/bonobo-listener.h>
#include <gal/util/e-util.h>
#define PARENT_TYPE gtk_object_get_type ()
static GtkObjectClass *parent_class = NULL;
/* The minimum time between updates, in msecs. */
#define UPDATE_DELAY 1000
enum {
SHOW_DETAILS,
CANCEL,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
struct _EvolutionActivityClientPrivate {
/* The ::Activity interface that we QI from the shell. */
GNOME_Evolution_Activity activity_interface;
/* BonoboListener used to get notification about actions that the user
requested on the activity. */
BonoboListener *listener;
/* Id of this activity. */
GNOME_Evolution_Activity_ActivityId activity_id;
/* Id for the GTK+ timeout used to do updates. */
int next_update_timeout_id;
/* Wether we have to actually push an update at this timeout. */
int have_pending_update;
/* Data for the next update. */
char *new_information;
double new_progress;
};
/* Utility functions. */
static gboolean
corba_update_progress (EvolutionActivityClient *activity_client,
const char *information,
double progress)
{
EvolutionActivityClientPrivate *priv;
CORBA_Environment ev;
gboolean retval;
priv = activity_client->priv;
CORBA_exception_init (&ev);
GNOME_Evolution_Activity_operationProgressing (priv->activity_interface,
priv->activity_id,
information,
progress,
&ev);
if (ev._major == CORBA_NO_EXCEPTION) {
retval = TRUE;
} else {
g_warning ("EvolutionActivityClient: Error updating progress -- %s",
ev._repo_id);
retval = FALSE;
}
CORBA_exception_free (&ev);
return retval;
}
static gboolean
update_timeout_callback (void *data)
{
EvolutionActivityClient *activity_client;
EvolutionActivityClientPrivate *priv;
activity_client = EVOLUTION_ACTIVITY_CLIENT (data);
priv = activity_client->priv;
if (priv->have_pending_update) {
priv->have_pending_update = FALSE;
corba_update_progress (activity_client, priv->new_information, priv->new_progress);
return TRUE;
} else {
priv->next_update_timeout_id = 0;
return FALSE;
}
}
/* BonoboListener callback. */
static void
listener_callback (BonoboListener *listener,
char *event_name,
CORBA_any *any,
CORBA_Environment *ev,
void *data)
{
EvolutionActivityClient *activity_client;
activity_client = EVOLUTION_ACTIVITY_CLIENT (data);
if (strcmp (event_name, "ShowDetails") == 0)
gtk_signal_emit (GTK_OBJECT (activity_client), signals[SHOW_DETAILS]);
else if (strcmp (event_name, "Cancel") == 0)
gtk_signal_emit (GTK_OBJECT (activity_client), signals[CANCEL]);
else
g_warning ("EvolutionActivityClient: Unknown event from listener -- %s", event_name);
}
/* GtkObject methods. */
static void
impl_destroy (GtkObject *object)
{
EvolutionActivityClient *activity_client;
EvolutionActivityClientPrivate *priv;
CORBA_Environment ev;
activity_client = EVOLUTION_ACTIVITY_CLIENT (object);
priv = activity_client->priv;
if (priv->next_update_timeout_id != 0)
g_source_remove (priv->next_update_timeout_id);
CORBA_exception_init (&ev);
if (! CORBA_Object_is_nil (priv->activity_interface, &ev)) {
GNOME_Evolution_Activity_operationFinished (priv->activity_interface,
priv->activity_id,
&ev);
if (ev._major != CORBA_NO_EXCEPTION)
g_warning ("EvolutionActivityClient: Error reporting completion of operation -- %s",
ev._repo_id);
CORBA_Object_release (priv->activity_interface, &ev);
}
CORBA_exception_free (&ev);
if (priv->listener != NULL)
bonobo_object_unref (BONOBO_OBJECT (priv->listener));
g_free (priv->new_information);
g_free (priv);
(* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
}
static void
class_init (EvolutionActivityClientClass *klass)
{
GtkObjectClass *object_class;
parent_class = gtk_type_class (PARENT_TYPE);
object_class = GTK_OBJECT_CLASS (klass);
object_class->destroy = impl_destroy;
signals[SHOW_DETAILS]
= gtk_signal_new ("show_details",
GTK_RUN_FIRST,
object_class->type,
GTK_SIGNAL_OFFSET (EvolutionActivityClientClass, show_details),
gtk_marshal_NONE__NONE,
GTK_TYPE_NONE, 0);
signals[CANCEL]
= gtk_signal_new ("cancel",
GTK_RUN_FIRST,
object_class->type,
GTK_SIGNAL_OFFSET (EvolutionActivityClientClass, cancel),
gtk_marshal_NONE__NONE,
GTK_TYPE_NONE, 0);
gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
}
static void
init (EvolutionActivityClient *activity_client)
{
EvolutionActivityClientPrivate *priv;
priv = g_new (EvolutionActivityClientPrivate, 1);
priv->activity_interface = CORBA_OBJECT_NIL;
priv->listener = bonobo_listener_new (listener_callback, activity_client);
priv->activity_id = (GNOME_Evolution_Activity_ActivityId) 0;
priv->next_update_timeout_id = 0;
priv->have_pending_update = FALSE;
priv->new_information = NULL;
priv->new_progress = 0.0;
activity_client->priv = priv;
}
gboolean
evolution_activity_client_construct (EvolutionActivityClient *activity_client,
EvolutionShellClient *shell_client,
const char *component_id,
GdkPixbuf **animated_icon,
const char *information,
gboolean cancellable,
gboolean *suggest_display_return)
{
EvolutionActivityClientPrivate *priv;
GNOME_Evolution_Activity activity_interface;
CORBA_Environment ev;
CORBA_boolean suggest_display;
GNOME_Evolution_AnimatedIcon *corba_animated_icon;
g_return_val_if_fail (activity_client != NULL, FALSE);
g_return_val_if_fail (EVOLUTION_IS_ACTIVITY_CLIENT (activity_client), FALSE);
g_return_val_if_fail (shell_client != NULL, FALSE);
g_return_val_if_fail (EVOLUTION_IS_SHELL_CLIENT (shell_client), FALSE);
g_return_val_if_fail (animated_icon != NULL, FALSE);
g_return_val_if_fail (*animated_icon != NULL, FALSE);
g_return_val_if_fail (information != NULL, FALSE);
g_return_val_if_fail (suggest_display_return != NULL, FALSE);
priv = activity_client->priv;
g_return_val_if_fail (priv->activity_interface == CORBA_OBJECT_NIL, FALSE);
GTK_OBJECT_UNSET_FLAGS (activity_client, GTK_FLOATING);
CORBA_exception_init (&ev);
activity_interface = evolution_shell_client_get_activity_interface (shell_client);
priv->activity_interface = CORBA_Object_duplicate (activity_interface, &ev);
if (ev._major != CORBA_NO_EXCEPTION) {
priv->activity_interface = CORBA_OBJECT_NIL;
CORBA_exception_free (&ev);
return FALSE;
}
corba_animated_icon = e_new_corba_animated_icon_from_pixbuf_array (animated_icon);
GNOME_Evolution_Activity_operationStarted (activity_interface,
component_id,
corba_animated_icon,
information,
cancellable,
bonobo_object_corba_objref (BONOBO_OBJECT (priv->listener)),
&priv->activity_id,
&suggest_display,
&ev);
CORBA_free (corba_animated_icon);
if (ev._major != CORBA_NO_EXCEPTION) {
CORBA_exception_free (&ev);
return FALSE;
}
*suggest_display_return = (gboolean) suggest_display;
CORBA_exception_free (&ev);
return TRUE;
}
EvolutionActivityClient *
evolution_activity_client_new (EvolutionShellClient *shell_client,
const char *component_id,
GdkPixbuf **animated_icon,
const char *information,
gboolean cancellable,
gboolean *suggest_display_return)
{
EvolutionActivityClient *activity_client;
g_return_val_if_fail (shell_client != NULL, NULL);
g_return_val_if_fail (EVOLUTION_IS_SHELL_CLIENT (shell_client), NULL);
g_return_val_if_fail (animated_icon != NULL, NULL);
g_return_val_if_fail (*animated_icon != NULL, NULL);
g_return_val_if_fail (information != NULL, NULL);
g_return_val_if_fail (suggest_display_return != NULL, NULL);
activity_client = gtk_type_new (evolution_activity_client_get_type ());
if (! evolution_activity_client_construct (activity_client,
shell_client,
component_id,
animated_icon,
information,
cancellable,
suggest_display_return)) {
gtk_object_unref (GTK_OBJECT (activity_client));
return NULL;
}
return activity_client;
}
gboolean
evolution_activity_client_update (EvolutionActivityClient *activity_client,
const char *information,
double progress)
{
EvolutionActivityClientPrivate *priv;
gboolean retval;
g_return_val_if_fail (activity_client != NULL, FALSE);
g_return_val_if_fail (EVOLUTION_IS_ACTIVITY_CLIENT (activity_client), FALSE);
g_return_val_if_fail (information != NULL, FALSE);
g_return_val_if_fail (progress == -1.0 || (progress >= 0.0 && progress <= 1.0), FALSE);
priv = activity_client->priv;
if (priv->next_update_timeout_id == 0) {
/* There is no pending timeout, so the last CORBA update
happened more than UPDATE_DELAY msecs ago. So we set up a
timeout so we can check against it at the next update
request.
Notice that GLib timeouts or other operations on this object
can be invoked within a remote CORBA invocation, so we need
to set `next_update_timeout_id' and `have_pending_update'
before doing the CORBA call, or nasty race conditions might
happen. */
priv->have_pending_update = FALSE;
priv->next_update_timeout_id = g_timeout_add (UPDATE_DELAY,
update_timeout_callback,
activity_client);
retval = corba_update_progress (activity_client, information, progress);
} else {
/* There is a pending timeout, so the last CORBA update
happened less than UPDATE_DELAY msecs ago. So just queue an
update instead. */
g_free (priv->new_information);
priv->new_information = g_strdup (information);
priv->new_progress = progress;
priv->have_pending_update = TRUE;
retval = TRUE;
}
return retval;
}
GNOME_Evolution_Activity_DialogAction
evolution_activity_client_request_dialog (EvolutionActivityClient *activity_client,
GNOME_Evolution_Activity_DialogType dialog_type)
{
EvolutionActivityClientPrivate *priv;
GNOME_Evolution_Activity_DialogAction retval;
CORBA_Environment ev;
g_return_val_if_fail (activity_client != NULL, GNOME_Evolution_Activity_DIALOG_ACTION_ERROR);
g_return_val_if_fail (EVOLUTION_IS_ACTIVITY_CLIENT (activity_client), GNOME_Evolution_Activity_DIALOG_ACTION_ERROR);
priv = activity_client->priv;
CORBA_exception_init (&ev);
retval = GNOME_Evolution_Activity_requestDialog (priv->activity_interface,
priv->activity_id,
dialog_type,
&ev);
if (ev._major != CORBA_NO_EXCEPTION) {
g_warning ("EvolutionActivityClient: Error requesting a dialog -- %s", ev._repo_id);
retval = GNOME_Evolution_Activity_DIALOG_ACTION_ERROR;
}
CORBA_exception_free (&ev);
return retval;
}
E_MAKE_TYPE (evolution_activity_client, "EvolutionActivityClient", EvolutionActivityClient,
class_init, init, PARENT_TYPE)