source: trunk/third/gnome-panel/gnome-panel/menu-ditem.c @ 18631

Revision 18631, 13.5 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18630, which included commits to RCS files with non-trunk default branches.
Line 
1#include <config.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5
6#include <libgnome/libgnome.h>
7#include <libgnomeui/libgnomeui.h>
8#include <libgnomevfs/gnome-vfs-mime.h>
9#include <libgnomevfs/gnome-vfs-uri.h>
10#include <libgnomevfs/gnome-vfs-ops.h>
11#include <libgnomevfs/gnome-vfs-directory.h>
12#include <libgnomevfs/gnome-vfs-utils.h>
13#include <libgnomeui/gnome-ditem-edit.h>
14
15#include "menu-ditem.h"
16#include "panel-util.h"
17
18enum {
19        REVERT_BUTTON
20};
21
22static void
23ditem_properties_clicked (GtkWidget *w, int response, gpointer data)
24{
25        GnomeDItemEdit *dee = g_object_get_data (G_OBJECT (w), "GnomeDItemEdit");
26        GnomeDesktopItem *ditem = data;
27
28        if (response == GTK_RESPONSE_HELP) {
29                panel_show_help (
30                        gtk_window_get_screen (GTK_WINDOW (w)),
31                        "wgospanel.xml", "gospanel-16");
32        } else if (response == REVERT_BUTTON) {
33                if (ditem != NULL)
34                        gnome_ditem_edit_set_ditem (dee, ditem);
35                else
36                        gnome_ditem_edit_clear (dee);
37        } else {
38                gtk_widget_destroy (w);
39        }
40}
41
42static gboolean
43ditem_properties_apply_timeout (gpointer data)
44{
45        GtkWidget *dedit = data;
46        GnomeDesktopItem *ditem;
47        const char *loc;
48        GError *error = NULL;
49
50        g_object_set_data (G_OBJECT (dedit), "apply_timeout", NULL);
51
52        ditem = gnome_ditem_edit_get_ditem (GNOME_DITEM_EDIT (dedit));
53        loc = g_object_get_data (G_OBJECT (dedit), "location");
54        gnome_desktop_item_save (ditem,
55                                 loc /* under */,
56                                 TRUE /* force */,
57                                 &error);
58        /* save the error for later */
59        if (error != NULL) {
60                g_object_set_data_full (G_OBJECT (dedit), "SavingError",
61                                        g_strdup (error->message),
62                                        (GDestroyNotify) g_free);
63                g_clear_error (&error);
64        } else {
65                g_object_set_data (G_OBJECT (dedit), "SavingError", NULL);
66        }
67
68        return FALSE;
69}
70
71/*
72 * Will save after 5 seconds of no changes.  If something is changed, the save
73 * is postponed to another 5 seconds.  This seems to be a saner behaviour,
74 * then just saving every N seconds.
75 */
76static void
77ditem_properties_changed (GtkWidget *dedit, gpointer data)
78{
79        gpointer timeout_data = g_object_get_data (G_OBJECT (dedit),
80                                                   "apply_timeout");
81        guint timeout = GPOINTER_TO_UINT (timeout_data);
82
83        g_object_set_data (G_OBJECT (dedit), "apply_timeout", NULL);
84
85        if (timeout != 0)
86                g_source_remove (timeout);
87
88        /* Will delay save for after 2 seconds */
89        timeout = g_timeout_add (2 * 1000,
90                                 ditem_properties_apply_timeout,
91                                 dedit);
92
93        g_object_set_data (G_OBJECT (dedit), "apply_timeout",
94                           GUINT_TO_POINTER (timeout));
95}
96
97
98static void
99ditem_properties_close (GtkWidget *dialog,
100                        GtkWidget *dedit)
101{
102        const char *saving_error;
103        gpointer timeout_data = g_object_get_data (G_OBJECT (dedit),
104                                                   "apply_timeout");
105        guint timeout = GPOINTER_TO_UINT (timeout_data);
106
107        g_object_set_data (G_OBJECT (dedit), "apply_timeout", NULL);
108
109        /* If there was a timeout, then something changed after last save,
110         * so we must save again now */
111        if (timeout != 0) {
112                g_source_remove (timeout);
113
114                ditem_properties_apply_timeout (dedit);
115        }
116
117        saving_error = g_object_get_data (G_OBJECT (dedit), "SavingError");
118
119        if (saving_error)
120                panel_error_dialog (
121                        gtk_window_get_screen (GTK_WINDOW (dialog)),
122                        "cannot_save_entry",
123                        _("<b>Cannot save changes to launcher</b>\n\n"
124                          "Details: %s"), saving_error);
125}
126
127static gboolean
128is_item_writable (const char *loc, const char *dir)
129{
130        if (loc != NULL) {
131                /* if old style kde link file, don't allow editing */
132                if (is_ext (loc, ".kdelnk"))
133                        return FALSE;
134                if (panel_is_uri_writable (loc))
135                        return TRUE;
136                else
137                        return FALSE;
138        }
139       
140        if (dir != NULL) {
141                if (panel_is_uri_writable (dir))
142                        return TRUE;
143                else
144                        return FALSE;
145        }
146
147        /* huh? */
148        return FALSE;
149}
150
151static void
152set_ditem_sensitive (GtkDialog *dialog,
153                     GnomeDItemEdit *dedit,
154                     const char *loc,
155                     const char *dir)
156{
157        gboolean sensitive;
158
159        sensitive = is_item_writable (loc, dir);
160
161        gnome_ditem_edit_set_editable (dedit, sensitive);
162
163        gtk_dialog_set_response_sensitive (dialog, REVERT_BUTTON, sensitive);
164}
165
166GtkWidget *
167panel_edit_dentry (const char *loc,
168                   const char *dir,
169                   GdkScreen  *screen)
170{
171        GnomeDesktopItem *ditem;
172        GtkWidget        *dialog;
173        GtkWidget        *dedit;
174       
175        g_return_val_if_fail (loc != NULL, NULL);
176
177        ditem = gnome_desktop_item_new_from_uri (loc, 0, NULL);         
178
179        dialog = gtk_dialog_new_with_buttons (
180                                _("Launcher Properties"),
181                                NULL, 0 /* flags */,
182                                GTK_STOCK_HELP,
183                                GTK_RESPONSE_HELP,
184                                GTK_STOCK_REVERT_TO_SAVED,
185                                REVERT_BUTTON,
186                                GTK_STOCK_CLOSE,
187                                GTK_RESPONSE_CLOSE,
188                                NULL);
189
190        gtk_dialog_set_default_response (
191                        GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
192
193        dedit = gnome_ditem_edit_new ();
194
195        gtk_widget_show (dedit);
196        gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
197                            dedit, TRUE, TRUE, 0);
198
199        gtk_window_set_wmclass (GTK_WINDOW (dialog),
200                                "desktop_entry_properties","Panel");
201        gtk_window_set_screen (GTK_WINDOW (dialog), screen);
202       
203        g_object_set_data_full (G_OBJECT (dedit), "location",
204                                g_strdup (loc),
205                                (GDestroyNotify)g_free);
206
207        if (ditem != NULL)
208                gnome_ditem_edit_set_ditem (GNOME_DITEM_EDIT (dedit), ditem);
209
210        set_ditem_sensitive (GTK_DIALOG (dialog),
211                             GNOME_DITEM_EDIT (dedit),
212                             loc, dir);
213
214        g_signal_connect (dedit, "changed",
215                          G_CALLBACK (ditem_properties_changed), NULL);
216
217        g_signal_connect (dialog, "destroy",
218                          G_CALLBACK (ditem_properties_close), dedit);
219
220        g_object_set_data (G_OBJECT (dialog), "GnomeDItemEdit", dedit);
221
222        if (ditem != NULL) {
223                /* pass the ditem as the data to clicked */
224                g_signal_connect_data (G_OBJECT (dialog), "response",
225                                       G_CALLBACK (ditem_properties_clicked),
226                                       ditem,
227                                       (GClosureNotify) gnome_desktop_item_unref,
228                                       0 /* connect_flags */);
229        } else {
230                g_signal_connect (G_OBJECT (dialog), "response",
231                                  G_CALLBACK (ditem_properties_clicked),
232                                  NULL);
233        }
234
235        gtk_widget_show (dialog);
236
237        gnome_ditem_edit_grab_focus (GNOME_DITEM_EDIT (dedit));
238
239        return dialog;
240}
241
242GtkWidget *
243panel_edit_direntry (const char *dir,
244                     const char *dir_name,
245                     GdkScreen  *screen)
246{
247        GtkWidget *dialog;
248        GtkWidget *dedit;
249        GnomeDesktopItem *ditem;
250        char *dirfile;
251       
252        dirfile = g_strconcat (dir, "/", ".directory", NULL);
253
254        ditem = gnome_desktop_item_new_from_uri (dirfile, 0, NULL);
255
256        dialog = gtk_dialog_new_with_buttons (
257                                _("Launcher Properties"),
258                                NULL, 0 /* flags */,
259                                GTK_STOCK_HELP,
260                                GTK_RESPONSE_HELP,
261                                GTK_STOCK_REVERT_TO_SAVED,
262                                REVERT_BUTTON,
263                                GTK_STOCK_CLOSE,
264                                GTK_RESPONSE_CLOSE,
265                                NULL);
266
267        gtk_window_set_wmclass (GTK_WINDOW (dialog),
268                                "desktop_entry_properties", "Panel");
269        gtk_window_set_screen (GTK_WINDOW (dialog), screen);
270       
271        dedit = gnome_ditem_edit_new ();
272        gtk_widget_show (dedit);
273        gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
274                            dedit, TRUE, TRUE, 0);
275
276        if (ditem != NULL) {
277                gnome_ditem_edit_set_ditem (GNOME_DITEM_EDIT (dedit), ditem);
278                g_object_set_data_full (G_OBJECT (dedit), "location",
279                                        g_strdup (gnome_desktop_item_get_location (ditem)),
280                                        (GDestroyNotify)g_free);
281        } else {
282                ditem = gnome_desktop_item_new ();
283                if (dir_name == NULL) {
284                        gnome_desktop_item_set_string (ditem,
285                                                       GNOME_DESKTOP_ITEM_NAME,
286                                                       "Menu");
287                        gnome_desktop_item_set_localestring
288                                (ditem,
289                                 GNOME_DESKTOP_ITEM_NAME,
290                                 _("Menu"));
291                } else {
292                        gnome_desktop_item_set_string (ditem,
293                                                       GNOME_DESKTOP_ITEM_NAME,
294                                                       dir_name);
295                }
296                gnome_desktop_item_set_string (ditem,
297                                               GNOME_DESKTOP_ITEM_TYPE,
298                                               "Directory");
299
300                /* we free dirfile below so make a copy here */
301                g_object_set_data_full (G_OBJECT (dedit),
302                                        "location", g_strdup (dirfile),
303                                        (GDestroyNotify)g_free);
304                gnome_ditem_edit_set_ditem (GNOME_DITEM_EDIT (dedit), ditem);
305        }
306
307        gnome_ditem_edit_set_directory_only (GNOME_DITEM_EDIT (dedit),
308                                             TRUE /* directory_only */);
309
310        set_ditem_sensitive (GTK_DIALOG (dialog),
311                             GNOME_DITEM_EDIT (dedit),
312                             dirfile, NULL);
313
314        g_signal_connect (dedit, "changed",
315                          G_CALLBACK (ditem_properties_changed), NULL);
316
317        g_signal_connect (dialog, "destroy",
318                          G_CALLBACK (ditem_properties_close), dedit);
319
320        g_object_set_data (G_OBJECT (dialog), "GnomeDItemEdit", dedit);
321
322        if (ditem != NULL) {
323                /* pass the dentry as the data to clicked */
324                g_signal_connect_data (G_OBJECT (dialog), "response",
325                                       G_CALLBACK (ditem_properties_clicked),
326                                       ditem,
327                                       (GClosureNotify) gnome_desktop_item_unref,
328                                       0 /* connect_flags */);
329        } else {
330                g_signal_connect (G_OBJECT (dialog), "response",
331                                    G_CALLBACK (ditem_properties_clicked),
332                                    NULL);
333        }
334
335        g_free (dirfile);
336               
337        gtk_widget_show (dialog);
338
339        gnome_ditem_edit_grab_focus (GNOME_DITEM_EDIT (dedit));
340
341        return dialog;
342}
343
344/* replaces '/' with returns _'s, originally from gmenu */
345static void
346validate_for_filename (char *file)
347{
348        char *ptr;
349
350        g_return_if_fail (file != NULL);
351       
352        ptr = file;
353        while (*ptr != '\0') {
354                if (*ptr == '/')
355                        *ptr = '_';
356                ptr++;
357        }
358}
359
360static char *
361get_schema (const char *dir)
362{
363        char *schema = g_strdup (dir);
364        char *p = strchr (schema, ':');
365        if (p == NULL) {
366                g_free (schema);
367                return NULL;
368        } else {
369                *p = '\0';
370                return schema;
371        }
372}
373
374static char *
375get_unique_name (const char *dir, const char *name)
376{
377        int i;
378        char *schema;
379        char *full, *test;
380        char *nameext = g_strdup_printf ("%s.desktop", name);
381
382        schema = get_schema (dir);
383
384        full = g_build_path ("/", dir, nameext, NULL);
385        if ( ! panel_uri_exists (full)) {
386                test = g_strdup_printf ("all-%s:%s", schema, nameext);
387                if ( ! panel_uri_exists (test)) {
388                        g_free (schema);
389                        g_free (test);
390                        g_free (nameext);
391                        return full;
392                }
393                g_free (test);
394        }
395        g_free (full);
396
397        i = 2;
398        for (;;) {
399                g_free (nameext);
400                nameext = g_strdup_printf ("%s%d.desktop", name, i++);
401
402                /* randomize further same name desktops */
403                if (i > 5)
404                        i = rand ();
405
406                full = g_build_path ("/", dir, nameext, NULL);
407                if ( ! panel_uri_exists (full)) {
408                        test = g_strdup_printf ("all-%s:%s", schema, nameext);
409                        if ( ! panel_uri_exists (test)) {
410                                g_free (schema);
411                                g_free (test);
412                                g_free (nameext);
413                                return full;
414                        }
415                        g_free (test);
416                }
417                g_free (full);
418        }
419}
420
421static void
422really_add_new_menu_item (GtkWidget *d, int response, gpointer data)
423{
424        GnomeDItemEdit *dedit = GNOME_DITEM_EDIT(data);
425        GnomeDesktopItem *ditem;
426        GError *error = NULL;
427        char *name, *loc, *dir;
428        GtkWidget *dialog;
429
430        if (response != GTK_RESPONSE_OK) {
431                gtk_widget_destroy (d);
432                return;
433        }
434
435        dir = g_object_get_data (G_OBJECT (d), "dir");
436        g_return_if_fail (dir != NULL);
437
438        panel_push_window_busy (d);
439
440        ditem = gnome_ditem_edit_get_ditem (dedit);
441
442        /* check for valid name */
443        if (string_empty (gnome_desktop_item_get_localestring (ditem, GNOME_DESKTOP_ITEM_NAME))) {
444                dialog = panel_error_dialog (
445                                gtk_window_get_screen (GTK_WINDOW (d)),
446                                "cannot_create_launcher",
447                                _("You have to specify a name for the launcher."));
448                g_signal_connect_swapped (G_OBJECT (dialog),
449                                          "destroy",
450                                          G_CALLBACK (panel_pop_window_busy),
451                                          G_OBJECT (d));
452                return;
453        }
454
455        /* check for valid URL or command */
456        if ((gnome_desktop_item_get_entry_type (ditem) == GNOME_DESKTOP_ITEM_TYPE_APPLICATION &&
457             string_empty (gnome_desktop_item_get_string (ditem, GNOME_DESKTOP_ITEM_EXEC))) ||
458            (gnome_desktop_item_get_entry_type (ditem) == GNOME_DESKTOP_ITEM_TYPE_LINK &&
459             string_empty (gnome_desktop_item_get_string (ditem, GNOME_DESKTOP_ITEM_URL)))) {
460                dialog = panel_error_dialog (
461                                gtk_window_get_screen (GTK_WINDOW (d)),
462                                "cannot_create_launcher",
463                                _("You have to specify a valid URL or command."));
464                g_signal_connect_swapped (G_OBJECT (dialog),
465                                          "destroy",
466                                          G_CALLBACK (panel_pop_window_busy),
467                                          G_OBJECT (d));
468                return;
469        }
470
471        /* assume we are making a new file */
472        name = g_filename_from_utf8 (gnome_desktop_item_get_localestring (ditem, GNOME_DESKTOP_ITEM_NAME),
473                                     -1, NULL, NULL, NULL);
474        if (name == NULL)
475                name = g_strdup ("foo");
476
477        validate_for_filename (name);
478
479        ditem = gnome_desktop_item_copy (ditem);
480
481        loc = get_unique_name (dir, name);
482        gnome_desktop_item_set_location (ditem, loc);
483        g_free (name);
484
485        error = NULL;
486        gnome_desktop_item_save (ditem,
487                                 NULL /* under */,
488                                 TRUE /* force */,
489                                 &error);
490        if (error) {
491                panel_error_dialog (
492                        gtk_window_get_screen (GTK_WINDOW (d)),
493                        "cannot_save_menu_item" /* class */,
494                        _("<b>Cannot save menu item to disk</b>\n\n"
495                          "Details: %s"),
496                        error->message);
497                g_clear_error (&error);
498        }
499
500        gnome_desktop_item_unref (ditem);
501
502        panel_pop_window_busy (d);
503
504        gtk_widget_destroy (d);
505        g_free (loc);
506}
507
508GtkWidget *
509panel_new_launcher (const char *item_loc,
510                    GdkScreen  *screen)
511{
512        GtkWidget *dialog;
513        GtkWidget *dee;
514
515        if (!is_item_writable (item_loc, NULL)) {
516                dialog = panel_error_dialog (
517                                screen,
518                                "cannot_create_launcher",
519                                _("You can not create a new launcher at this location "
520                                  "since the location is not writable."));
521
522                return dialog;
523        }
524
525        dialog = gtk_dialog_new_with_buttons (
526                                _("Create Launcher"),
527                                NULL, 0 /* flags */,
528                                GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
529                                GTK_STOCK_OK, GTK_RESPONSE_OK,
530                                NULL);
531
532        gtk_window_set_wmclass (GTK_WINDOW (dialog),
533                               "create_menu_item", "Panel");
534        gtk_window_set_screen (GTK_WINDOW (dialog), screen);
535       
536        dee = gnome_ditem_edit_new ();
537        gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), dee,
538                            TRUE, TRUE, GNOME_PAD_SMALL);
539
540        gnome_ditem_edit_set_entry_type (GNOME_DITEM_EDIT (dee),
541                                         "Application");
542
543        g_object_set_data_full (G_OBJECT (dialog), "dir",
544                                g_strdup (item_loc),
545                                (GDestroyNotify)g_free);
546       
547        g_signal_connect (G_OBJECT (dialog), "response",
548                          G_CALLBACK (really_add_new_menu_item),
549                          dee);
550
551        gtk_dialog_set_default_response (GTK_DIALOG(dialog),
552                                         GTK_RESPONSE_OK);
553
554        gtk_widget_show_all (dialog);
555
556        gnome_ditem_edit_grab_focus (GNOME_DITEM_EDIT (dee));
557
558        return dialog;
559}
Note: See TracBrowser for help on using the repository browser.