source: trunk/third/evolution/shell/e-shell-folder-selection-dialog.c @ 18142

Revision 18142, 16.7 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18141, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2/* e-shell-folder-selection-dialog.c
3 *
4 * Copyright (C) 2000, 2001 Ximian, Inc.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 *
20 * Author: Ettore Perazzoli
21 */
22
23#ifdef HAVE_CONFIG_H
24#include <config.h>
25#endif
26
27#include <libgnomeui/gnome-stock.h>
28#include <libgnomeui/gnome-dialog.h>
29#include <libgnome/gnome-i18n.h>
30
31#include <gal/util/e-util.h>
32#include <gal/widgets/e-scroll-frame.h>
33#include <gal/widgets/e-gui-utils.h>
34
35#include "e-shell-constants.h"
36#include "e-storage-set-view.h"
37#include "e-storage-set.h"
38
39#include "e-shell-folder-creation-dialog.h"
40
41#include "e-shell-folder-selection-dialog.h"
42
43
44#define PARENT_TYPE (gnome_dialog_get_type ())
45static GnomeDialogClass *parent_class = NULL;
46
47struct _EShellFolderSelectionDialogPrivate {
48        EShell *shell;
49        GList *allowed_types;
50        EStorageSet *storage_set;
51        GtkWidget *storage_set_view;
52
53        gboolean allow_creation;
54};
55
56enum {
57        FOLDER_SELECTED,
58        CANCELLED,
59        LAST_SIGNAL
60};
61
62static guint signals[LAST_SIGNAL] = { 0 };
63
64
65/* Utility functions.  */
66
67static gboolean
68check_folder_type_valid (EShellFolderSelectionDialog *folder_selection_dialog)
69{
70        EShellFolderSelectionDialogPrivate *priv;
71        const char *selected_path;
72        EFolder *folder;
73        const char *folder_type;
74        GList *p;
75
76        priv = folder_selection_dialog->priv;
77        if (priv->allowed_types == NULL)
78                return TRUE;
79
80        selected_path = e_shell_folder_selection_dialog_get_selected_path (folder_selection_dialog);
81        if (selected_path == NULL)
82                return FALSE;
83
84        folder = e_storage_set_get_folder (priv->storage_set, selected_path);
85        if (folder == NULL)
86                return FALSE;
87
88        folder_type = e_folder_get_type_string (folder);
89
90        for (p = priv->allowed_types; p != NULL; p = p->next) {
91                const char *type, *slash;
92
93                type = (const char *) p->data;
94                if (strcasecmp (folder_type, type) == 0)
95                        return TRUE;
96                slash = strchr (type, '/');
97                if (slash && slash[1] == '*' &&
98                    g_strncasecmp (folder_type, type, slash - type) == 0)
99                        return TRUE;
100        }
101
102        return FALSE;
103}
104
105static void
106set_default_folder (EShellFolderSelectionDialog *shell_folder_selection_dialog,
107                    const char *default_uri)
108{
109        EShellFolderSelectionDialogPrivate *priv;
110        char *default_path;
111
112        g_assert (default_uri != NULL);
113
114        priv = shell_folder_selection_dialog->priv;
115
116        if (strncmp (default_uri, E_SHELL_URI_PREFIX, E_SHELL_URI_PREFIX_LEN) == 0) {
117                /* `evolution:' URI.  */
118                default_path = g_strdup (default_uri + E_SHELL_URI_PREFIX_LEN);
119        } else {
120                /* Physical URI.  */
121                default_path = e_storage_set_get_path_for_physical_uri (priv->storage_set,
122                                                                        default_uri);
123        }
124
125        e_storage_set_view_set_current_folder (E_STORAGE_SET_VIEW (priv->storage_set_view),
126                                               default_path);
127
128        g_free (default_path);
129}
130
131
132/* Folder creation dialog callback.  */
133
134static void
135folder_creation_dialog_result_cb (EShell *shell,
136                                  EShellFolderCreationDialogResult result,
137                                  const char *path,
138                                  void *data)
139{
140        EShellFolderSelectionDialog *dialog;
141        EShellFolderSelectionDialogPrivate *priv;
142
143        dialog = E_SHELL_FOLDER_SELECTION_DIALOG (data);
144        priv = dialog->priv;
145
146        if (priv == NULL) {
147                g_warning ("dialog->priv is NULL, and should not be");
148                return;
149        }
150
151        if (result == E_SHELL_FOLDER_CREATION_DIALOG_RESULT_SUCCESS)
152                e_storage_set_view_set_current_folder (E_STORAGE_SET_VIEW (priv->storage_set_view),
153                                                       path);
154}
155
156
157/* GtkObject methods.  */
158
159/* Saves the expanded state of the tree to a common filename */
160static void
161save_expanded_state (EShellFolderSelectionDialog *folder_selection_dialog)
162{
163        EShellFolderSelectionDialogPrivate *priv;
164        char *filename;
165
166        priv = folder_selection_dialog->priv;
167
168        filename = g_strdup_printf ("%s/config/storage-set-view-expanded:folder-selection-dialog",
169                                    e_shell_get_local_directory (priv->shell));
170        e_tree_save_expanded_state (E_TREE (priv->storage_set_view), filename);
171        g_free (filename);
172}
173
174static void
175impl_destroy (GtkObject *object)
176{
177        EShellFolderSelectionDialog *folder_selection_dialog;
178        EShellFolderSelectionDialogPrivate *priv;
179
180        folder_selection_dialog = E_SHELL_FOLDER_SELECTION_DIALOG (object);
181        priv = folder_selection_dialog->priv;
182
183        save_expanded_state (folder_selection_dialog);
184
185        if (priv->storage_set != NULL)
186                gtk_object_unref (GTK_OBJECT (priv->storage_set));
187
188        e_free_string_list (priv->allowed_types);
189
190        g_free (priv);
191
192        (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
193}
194
195
196/* GnomeDialog methods.  */
197
198static void
199impl_clicked (GnomeDialog *dialog,
200              int button_number)
201{
202        EShellFolderSelectionDialog *folder_selection_dialog;
203        EShellFolderSelectionDialogPrivate *priv;
204        EStorageSetView *storage_set_view;
205        const char *default_parent_folder;
206        const char *default_subtype;
207        char *default_type;
208
209        folder_selection_dialog = E_SHELL_FOLDER_SELECTION_DIALOG (dialog);
210        priv = folder_selection_dialog->priv;
211
212        switch (button_number) {
213        case 0:                 /* OK */
214                if (check_folder_type_valid (folder_selection_dialog)) {
215                        gtk_signal_emit (GTK_OBJECT (folder_selection_dialog), signals[FOLDER_SELECTED],
216                                         e_shell_folder_selection_dialog_get_selected_path (folder_selection_dialog));
217                        gnome_dialog_close (GNOME_DIALOG (dialog));
218                }
219                break;
220        case 1:                 /* Cancel */
221                gtk_signal_emit (GTK_OBJECT (folder_selection_dialog), signals[CANCELLED]);
222                gnome_dialog_close (GNOME_DIALOG (dialog));
223                break;
224        case 2:                 /* Add */
225                storage_set_view = E_STORAGE_SET_VIEW (priv->storage_set_view);
226                default_parent_folder = e_storage_set_view_get_current_folder (storage_set_view);
227
228                /* The default type in the folder creation dialog will be the
229                   first of the allowed types.  If all types are allowed,
230                   hardcode to "mail".  */
231                if (priv->allowed_types == NULL)
232                        default_type = g_strdup ("mail");
233                else {
234                        default_subtype = (const char *) priv->allowed_types->data;
235                        default_type = g_strndup (default_subtype,
236                                                  strcspn (default_subtype, "/"));
237                }
238
239                e_shell_show_folder_creation_dialog (priv->shell, GTK_WINDOW (dialog),
240                                                     default_parent_folder,
241                                                     default_type,
242                                                     folder_creation_dialog_result_cb,
243                                                     dialog);
244                g_free (default_type);
245
246                break;
247        }
248}
249
250
251/* GTK+ type initialization.  */
252
253static void
254class_init (EShellFolderSelectionDialogClass *klass)
255{
256        GtkObjectClass *object_class;
257        GnomeDialogClass *dialog_class;
258
259        parent_class = gtk_type_class (PARENT_TYPE);
260        object_class = GTK_OBJECT_CLASS (klass);
261        dialog_class = GNOME_DIALOG_CLASS (klass);
262
263        object_class->destroy = impl_destroy;
264
265        dialog_class->clicked = impl_clicked;
266
267        signals[FOLDER_SELECTED]
268                = gtk_signal_new ("folder_selected",
269                                  GTK_RUN_LAST,
270                                  object_class->type,
271                                  GTK_SIGNAL_OFFSET (EShellFolderSelectionDialogClass, folder_selected),
272                                  gtk_marshal_NONE__POINTER,
273                                  GTK_TYPE_NONE, 1,
274                                  GTK_TYPE_STRING);
275
276        signals[CANCELLED]
277                = gtk_signal_new ("cancelled",
278                                  GTK_RUN_LAST,
279                                  object_class->type,
280                                  GTK_SIGNAL_OFFSET (EShellFolderSelectionDialogClass, cancelled),
281                                  gtk_marshal_NONE__NONE,
282                                  GTK_TYPE_NONE, 0);
283
284        gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
285}
286
287static void
288init (EShellFolderSelectionDialog *shell_folder_selection_dialog)
289{
290        EShellFolderSelectionDialogPrivate *priv;
291
292        priv = g_new (EShellFolderSelectionDialogPrivate, 1);
293        priv->shell            = NULL;
294        priv->storage_set      = NULL;
295        priv->storage_set_view = NULL;
296        priv->allowed_types    = NULL;
297        priv->allow_creation   = TRUE;
298
299        shell_folder_selection_dialog->priv = priv;
300}
301
302
303/* ETable callbacks.  */
304
305static void
306folder_selected_cb (EStorageSetView *storage_set_view,
307                    const char *path,
308                    void *data)
309{
310        EShellFolderSelectionDialog *dialog;
311
312        dialog = E_SHELL_FOLDER_SELECTION_DIALOG (data);
313
314        if (check_folder_type_valid (dialog))
315                gnome_dialog_set_sensitive (GNOME_DIALOG (dialog), 0, TRUE);
316        else
317                gnome_dialog_set_sensitive (GNOME_DIALOG (dialog), 0, FALSE);
318}
319
320static gint
321delete_event_cb (GtkWidget *w, GdkEvent *event, gpointer data)
322{
323        EShellFolderSelectionDialog *dialog = data;
324
325        gtk_signal_emit (GTK_OBJECT (dialog), signals[CANCELLED]);
326
327        return TRUE;
328}
329
330static void
331double_click_cb (EStorageSetView *essv,
332                 int row,
333                 ETreePath path,
334                 int col,
335                 GdkEvent *event,
336                 EShellFolderSelectionDialog *folder_selection_dialog)
337{
338        g_return_if_fail (folder_selection_dialog != NULL);
339
340        if (check_folder_type_valid (folder_selection_dialog)) {
341                gtk_signal_emit (GTK_OBJECT (folder_selection_dialog),
342                                 signals[FOLDER_SELECTED],
343                                 e_shell_folder_selection_dialog_get_selected_path (folder_selection_dialog));
344                gnome_dialog_close (GNOME_DIALOG (folder_selection_dialog));
345        }
346}
347
348
349/**
350 * e_shell_folder_selection_dialog_construct:
351 * @folder_selection_dialog: A folder selection dialog widget
352 * @shell: The this folder selection dialog is for
353 * @title: Title of the window
354 * @caption: A brief text to be put on top of the storage view
355 * @default_uri: The URI of the folder to be selected by default
356 * @allowed_types: List of the names of the allowed types
357 *
358 * Construct @folder_selection_dialog.
359 **/
360void
361e_shell_folder_selection_dialog_construct (EShellFolderSelectionDialog *folder_selection_dialog,
362                                           EShell *shell,
363                                           const char *title,
364                                           const char *caption,
365                                           const char *default_uri,
366                                           const char *allowed_types[])
367{
368        EShellFolderSelectionDialogPrivate *priv;
369        GtkWidget *scroll_frame;
370        GtkWidget *caption_label;
371        int i;
372        char *filename;
373
374        g_return_if_fail (folder_selection_dialog != NULL);
375        g_return_if_fail (E_IS_SHELL_FOLDER_SELECTION_DIALOG (folder_selection_dialog));
376        g_return_if_fail (shell != NULL);
377        g_return_if_fail (E_IS_SHELL (shell));
378
379        priv = folder_selection_dialog->priv;
380
381        /* Basic dialog setup.  */
382
383        gtk_window_set_policy (GTK_WINDOW (folder_selection_dialog), FALSE, TRUE, FALSE);
384        gtk_window_set_default_size (GTK_WINDOW (folder_selection_dialog), 350, 300);
385        gtk_window_set_modal (GTK_WINDOW (folder_selection_dialog), TRUE);
386        gtk_window_set_title (GTK_WINDOW (folder_selection_dialog), title);
387        gtk_signal_connect (GTK_OBJECT (folder_selection_dialog), "delete_event",
388                            GTK_SIGNAL_FUNC (delete_event_cb), folder_selection_dialog);
389
390        gnome_dialog_append_buttons (GNOME_DIALOG (folder_selection_dialog),
391                                     GNOME_STOCK_BUTTON_OK,
392                                     GNOME_STOCK_BUTTON_CANCEL,
393                                     _("New..."),
394                                     NULL);
395        gnome_dialog_set_default (GNOME_DIALOG (folder_selection_dialog), 0);
396        gnome_dialog_set_sensitive (GNOME_DIALOG (folder_selection_dialog), 0, FALSE);
397
398        /* Make sure we get destroyed if the shell gets destroyed.  */
399
400        priv->shell = shell;
401        gtk_signal_connect_object_while_alive (GTK_OBJECT (shell), "destroy",
402                                               GTK_SIGNAL_FUNC (gtk_widget_destroy),
403                                               GTK_OBJECT (folder_selection_dialog));
404
405        /* Set up the label.  */
406
407        if (caption != NULL) {
408                caption_label = gtk_label_new (caption);
409                gtk_widget_show (caption_label);
410
411                gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (folder_selection_dialog)->vbox),
412                                    caption_label, FALSE, TRUE, 2);
413        }
414
415        /* Set up the storage set and its view.  */
416
417        priv->storage_set = e_shell_get_storage_set (shell);
418        gtk_object_ref (GTK_OBJECT (priv->storage_set));
419
420        priv->storage_set_view = e_storage_set_create_new_view (priv->storage_set, NULL);
421        e_storage_set_view_set_allow_dnd (E_STORAGE_SET_VIEW (priv->storage_set_view), FALSE);
422        e_storage_set_view_enable_search (E_STORAGE_SET_VIEW (priv->storage_set_view), TRUE);
423
424        /* Load the expanded state for this StorageSetView */
425        filename = g_strdup_printf ("%s/config/storage-set-view-expanded:folder-selection-dialog",
426                                    e_shell_get_local_directory (priv->shell));
427
428        e_tree_load_expanded_state (E_TREE (priv->storage_set_view),
429                                    filename);
430
431        g_free (filename);
432
433        gtk_signal_connect (GTK_OBJECT (priv->storage_set_view), "double_click",
434                            GTK_SIGNAL_FUNC (double_click_cb),
435                            folder_selection_dialog);
436        gtk_signal_connect (GTK_OBJECT (priv->storage_set_view), "folder_selected",
437                            GTK_SIGNAL_FUNC (folder_selected_cb),
438                            folder_selection_dialog);
439
440        g_assert (priv->allowed_types == NULL);
441        if (allowed_types != NULL) {
442                for (i = 0; allowed_types[i] != NULL; i++)
443                        priv->allowed_types = g_list_prepend (priv->allowed_types,
444                                                              g_strdup (allowed_types[i]));
445
446                /* Preserve the order so we can use the first type listed as
447                   the default for the folder creation dialog invoked by the
448                   "New..." button.  */
449                priv->allowed_types = g_list_reverse (priv->allowed_types);
450        }
451
452        if (default_uri != NULL)
453                set_default_folder (folder_selection_dialog, default_uri);
454
455        scroll_frame = e_scroll_frame_new (NULL, NULL);
456        e_scroll_frame_set_shadow_type (E_SCROLL_FRAME (scroll_frame), GTK_SHADOW_IN);
457        e_scroll_frame_set_policy (E_SCROLL_FRAME (scroll_frame),
458                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
459
460        gtk_container_add (GTK_CONTAINER (scroll_frame), priv->storage_set_view);
461
462        gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (folder_selection_dialog)->vbox),
463                            scroll_frame, TRUE, TRUE, 2);
464
465        gtk_widget_show (priv->storage_set_view);
466        gtk_widget_show (scroll_frame);
467
468        GTK_WIDGET_SET_FLAGS (priv->storage_set_view, GTK_CAN_FOCUS);
469        gtk_widget_grab_focus (priv->storage_set_view);
470}
471
472/**
473 * e_shell_folder_selection_dialog_new:
474 * @shell: The this folder selection dialog is for
475 * @title: Title of the window
476 * @caption: A brief text to be put on top of the storage view
477 * @default_uri: The URI of the folder to be selected by default
478 * @allowed_types: List of the names of the allowed types
479 *
480 * Create a new folder selection dialog widget.  @default_uri can be either an
481 * `evolution:' URI or a physical URI (all the non-`evolution:' URIs are
482 * considered to be physical URIs).
483 *
484 * Return value:
485 **/
486GtkWidget *
487e_shell_folder_selection_dialog_new (EShell *shell,
488                                     const char *title,
489                                     const char *caption,
490                                     const char *default_uri,
491                                     const char *allowed_types[])
492{
493        EShellFolderSelectionDialog *folder_selection_dialog;
494
495        g_return_val_if_fail (shell != NULL, NULL);
496        g_return_val_if_fail (E_IS_SHELL (shell), NULL);
497
498        folder_selection_dialog = gtk_type_new (e_shell_folder_selection_dialog_get_type ());
499        e_shell_folder_selection_dialog_construct (folder_selection_dialog, shell,
500                                                   title, caption, default_uri, allowed_types);
501
502        return GTK_WIDGET (folder_selection_dialog);
503}
504
505
506/**
507 * e_shell_folder_selection_dialog_set_allow_creation:
508 * @folder_selection_dialog: An EShellFolderSelectionDialog widget
509 * @allow_creation: Boolean specifying whether the "New..." button should be
510 * displayed
511 *
512 * Specify whether @folder_selection_dialog should have a "New..." button to
513 * create a new folder or not.
514 **/
515void
516e_shell_folder_selection_dialog_set_allow_creation (EShellFolderSelectionDialog *folder_selection_dialog,
517                                                    gboolean allow_creation)
518{
519        GList *button_list_item;
520        GtkWidget *button;
521
522        g_return_if_fail (folder_selection_dialog != NULL);
523        g_return_if_fail (E_IS_SHELL_FOLDER_SELECTION_DIALOG (folder_selection_dialog));
524
525        folder_selection_dialog->priv->allow_creation = !! allow_creation;
526
527        button_list_item = g_list_nth (GNOME_DIALOG (folder_selection_dialog)->buttons, 2);
528        g_assert (button_list_item != NULL);
529
530        button = GTK_WIDGET (button_list_item->data);
531
532        if (allow_creation)
533                gtk_widget_show (button);
534        else
535                gtk_widget_hide (button);
536}
537
538/**
539 * e_shell_folder_selection_dialog_get_allow_creation:
540 * @folder_selection_dialog: An EShellFolderSelectionDialog widget
541 *
542 * Get whether the "New..." button is displayed.
543 *
544 * Return value: %TRUE if the "New..." button is displayed, %FALSE otherwise.
545 **/
546gboolean
547e_shell_folder_selection_dialog_get_allow_creation (EShellFolderSelectionDialog *folder_selection_dialog)
548{
549        g_return_val_if_fail (folder_selection_dialog != NULL, FALSE);
550        g_return_val_if_fail (E_IS_SHELL_FOLDER_SELECTION_DIALOG (folder_selection_dialog), FALSE);
551
552        return folder_selection_dialog->priv->allow_creation;
553}
554
555
556const char *
557e_shell_folder_selection_dialog_get_selected_path (EShellFolderSelectionDialog *folder_selection_dialog)
558{
559        EShellFolderSelectionDialogPrivate *priv;
560
561        g_return_val_if_fail (folder_selection_dialog != NULL, NULL);
562        g_return_val_if_fail (E_IS_SHELL_FOLDER_SELECTION_DIALOG (folder_selection_dialog), NULL);
563
564        priv = folder_selection_dialog->priv;
565
566        return e_storage_set_view_get_current_folder (E_STORAGE_SET_VIEW (priv->storage_set_view));
567}
568
569
570E_MAKE_TYPE (e_shell_folder_selection_dialog, "EShellFolderSelectionDialog", EShellFolderSelectionDialog,
571             class_init, init, PARENT_TYPE)
Note: See TracBrowser for help on using the repository browser.