]> www.fi.muni.cz Git - evince.git/blob - cut-n-paste/recent-files/egg-recent-view-bonobo.c
PDFDoc constructor assumes ownership of the string passed in.
[evince.git] / cut-n-paste / recent-files / egg-recent-view-bonobo.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /**
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as
5  * published by the Free Software Foundation; either version 2 of the
6  * License, or (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
16  *
17  * Authors:
18  *   James Willcox <jwillcox@cs.indiana.edu>
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <gtk/gtk.h>
29 #include <libbonoboui.h>
30 #include <libgnomevfs/gnome-vfs.h>
31 #ifndef USE_STABLE_LIBGNOMEUI
32 #include <libgnomeui/gnome-icon-theme.h>
33 #endif
34 #include <gconf/gconf-client.h>
35 #include "egg-recent-model.h"
36 #include "egg-recent-view.h"
37 #include "egg-recent-view-bonobo.h"
38 #include "egg-recent-util.h"
39 #include "egg-recent-item.h"
40
41 struct _EggRecentViewBonobo {
42         GObject parent_instance;        /* We emit signals */
43
44         BonoboUIComponent *uic;
45         gchar *path;                    /* The menu path where our stuff
46                                          *  will go
47                                          */
48
49         gulong changed_cb_id;
50
51         gchar *uid;                     /* unique id used for the verb name */
52
53         gboolean show_icons;
54         gboolean show_numbers;
55 #ifndef USE_STABLE_LIBGNOMEUI
56         GnomeIconTheme *theme;
57 #endif
58         EggRecentViewBonoboTooltipFunc tooltip_func;
59         gpointer tooltip_func_data;
60
61         EggRecentModel *model;
62         GConfClient *client;
63         GtkIconSize icon_size;
64 };
65
66
67 struct _EggRecentViewBonoboMenuData {
68         EggRecentViewBonobo *view;
69         EggRecentItem *item;
70 };
71
72 typedef struct _EggRecentViewBonoboMenuData EggRecentViewBonoboMenuData;
73
74 enum {
75         ACTIVATE,
76         LAST_SIGNAL
77 };
78
79 /* GObject properties */
80 enum {
81         PROP_BOGUS,
82         PROP_UI_COMPONENT,
83         PROP_MENU_PATH,
84         PROP_SHOW_ICONS,
85         PROP_SHOW_NUMBERS
86 };
87
88 static guint egg_recent_view_bonobo_signals[LAST_SIGNAL] = { 0 };
89
90 static void
91 egg_recent_view_bonobo_clear (EggRecentViewBonobo *view)
92 {
93         gint i=1;
94         gboolean done=FALSE;
95         EggRecentModel *model;
96
97         g_return_if_fail (view->uic);
98
99         model = egg_recent_view_get_model (EGG_RECENT_VIEW (view));
100         
101         while (!done)
102         {
103                 gchar *verb_name = g_strdup_printf ("%s-%d", view->uid, i);
104                 gchar *item_path = g_strconcat (view->path, "/", verb_name, NULL);
105                 if (bonobo_ui_component_path_exists (view->uic, item_path, NULL))
106                         bonobo_ui_component_rm (view->uic, item_path, NULL);
107                 else
108                         done=TRUE;
109
110                 g_free (item_path);
111                 g_free (verb_name);
112
113                 i++;
114         }
115 }
116
117 static void
118 egg_recent_view_bonobo_menu_cb (BonoboUIComponent *uic, gpointer data, const char *cname)
119 {
120         EggRecentViewBonoboMenuData *md = (EggRecentViewBonoboMenuData *) data;
121         EggRecentItem *item;
122
123         g_return_if_fail (md);
124         g_return_if_fail (md->item);
125         g_return_if_fail (md->view);
126         g_return_if_fail (EGG_IS_RECENT_VIEW_BONOBO (md->view));
127
128         item = md->item;
129         egg_recent_item_ref (item);
130
131         g_signal_emit (G_OBJECT(md->view),
132                        egg_recent_view_bonobo_signals[ACTIVATE], 0,
133                        item);
134
135         egg_recent_item_unref (item);
136 }
137
138 static void
139 egg_recent_view_bonobo_menu_data_destroy_cb (gpointer data, GClosure *closure)
140 {
141         EggRecentViewBonoboMenuData *md = data;
142
143         egg_recent_item_unref (md->item);
144         g_free (md);
145 }
146
147
148 static void
149 egg_recent_view_bonobo_set_list (EggRecentViewBonobo *view, GList *list)
150 {
151         BonoboUIComponent* ui_component;
152         unsigned int i;
153         gchar *label = NULL;
154         gchar *verb_name = NULL;
155         gchar *tip = NULL;
156         gchar *escaped_name = NULL;
157         gchar *item_path = NULL;
158         gchar *base_uri;
159         gchar *utf8_uri;
160         gchar *cmd;
161         gchar *xml_escaped_name;
162         EggRecentViewBonoboMenuData *md;
163         EggRecentModel *model;
164         GClosure *closure;
165
166         g_return_if_fail (view);
167
168         ui_component = view->uic;
169         g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui_component));
170
171
172         model = egg_recent_view_get_model (EGG_RECENT_VIEW (view));
173
174         egg_recent_view_bonobo_clear (view);
175
176         
177         bonobo_ui_component_freeze (ui_component, NULL);
178
179         for (i = 1; i <= g_list_length (list); ++i)
180         {
181                 EggRecentItem *item = (EggRecentItem *)g_list_nth_data (list, i-1);     
182
183                 utf8_uri = egg_recent_item_get_uri_for_display (item);
184                 if (utf8_uri == NULL)
185                         continue;
186                 
187                 /* this is what gets passed to our private "activate" callback */
188                 md = (EggRecentViewBonoboMenuData *)g_malloc (sizeof (EggRecentViewBonoboMenuData));
189                 md->view = view;
190                 md->item = item;
191
192                 egg_recent_item_ref (md->item);
193
194                 base_uri = g_path_get_basename (utf8_uri);
195                 xml_escaped_name = g_markup_escape_text (base_uri,
196                                                          strlen (base_uri));
197         
198                 escaped_name = egg_recent_util_escape_underlines (xml_escaped_name);
199                 g_free (xml_escaped_name);
200
201                 tip = NULL;
202                 if (view->tooltip_func != NULL) {
203                         gchar *tmp_tip;
204                         tip = view->tooltip_func (item,
205                                                   view->tooltip_func_data);
206                         tmp_tip = g_markup_escape_text (tip, strlen (tip));
207                         g_free (tip);
208                         tip = tmp_tip;
209                 }
210
211                 if (tip == NULL)
212                         tip = g_strdup ("");
213
214                 verb_name = g_strdup_printf ("%s-%d", view->uid, i);
215
216                 if (view->show_icons) {
217                         GdkPixbuf *pixbuf;
218                         gchar *mime_type;
219                         gchar *uri;
220
221                         mime_type = egg_recent_item_get_mime_type (item);
222                         uri = egg_recent_item_get_uri (item);
223 #ifndef USE_STABLE_LIBGNOMEUI
224                         {
225                                 int width, height;
226
227                                 gtk_icon_size_lookup_for_settings
228                                         (gtk_settings_get_default (),
229                                          view->icon_size,
230                                          &width, &height);
231                                 pixbuf = egg_recent_util_get_icon
232                                                         (view->theme,
233                                                          uri, mime_type,
234                                                          height);
235                         }
236 #else
237                         pixbuf = NULL;
238 #endif
239
240
241                         if (pixbuf != NULL) {
242                                 gchar *pixbuf_xml;
243
244                                 /* Riiiiight.... */
245                                 pixbuf_xml = bonobo_ui_util_pixbuf_to_xml (pixbuf);
246                                 
247                                 cmd = g_strdup_printf ("<cmd name=\"%s\" pixtype=\"pixbuf\" pixname=\"%s\"/>", verb_name, pixbuf_xml);
248
249                                 g_free (pixbuf_xml);
250                                 g_object_unref (pixbuf);
251                         } else {
252                                 cmd = g_strdup_printf ("<cmd name=\"%s\"/> ",
253                                                        verb_name);
254                         }
255
256                         g_free (mime_type);
257                         g_free (uri);
258                 } else
259                         cmd = g_strdup_printf ("<cmd name=\"%s\"/> ",
260                                                verb_name);
261                 bonobo_ui_component_set_translate (ui_component, "/commands/", cmd, NULL);
262
263                 closure = g_cclosure_new (G_CALLBACK (egg_recent_view_bonobo_menu_cb),
264                                           md, egg_recent_view_bonobo_menu_data_destroy_cb);
265                                           
266                 bonobo_ui_component_add_verb_full (ui_component, verb_name,
267                                                    closure); 
268                 
269                 if (view->show_numbers) {
270                         if (i < 10)
271                                 label = g_strdup_printf ("_%d. %s", i,
272                                                          escaped_name);
273                         else
274                                 label = g_strdup_printf ("%d. %s", i, escaped_name);
275                 } else {
276                         label = g_strdup (escaped_name);
277                 }
278                         
279                 
280                 
281                 item_path = g_strconcat (view->path, "/", verb_name, NULL);
282
283                 if (bonobo_ui_component_path_exists (ui_component, item_path, NULL))
284                 {
285                         bonobo_ui_component_set_prop (ui_component, item_path, 
286                                                       "label", label, NULL);
287
288                         bonobo_ui_component_set_prop (ui_component, item_path, 
289                                                       "tip", tip, NULL);
290                 }
291                 else
292                 {
293                         gchar *xml;
294                         
295                         xml = g_strdup_printf ("<menuitem name=\"%s\" "
296                                                 "verb=\"%s\""
297                                                 " _label=\"%s\"  _tip=\"%s\" "
298                                                 "hidden=\"0\" />", 
299                                                 verb_name, verb_name, label,
300                                                 tip);
301
302                         bonobo_ui_component_set_translate (ui_component, view->path, xml, NULL);
303
304                         g_free (xml); 
305                 }
306                 
307                 g_free (label);
308                 g_free (verb_name);
309                 g_free (tip);
310                 g_free (escaped_name);
311                 g_free (item_path);
312                 g_free (utf8_uri);
313                 g_free (base_uri);
314                 g_free (cmd);
315
316         }
317
318
319         bonobo_ui_component_thaw (ui_component, NULL);
320 }
321
322 static void
323 model_changed_cb (EggRecentModel *model, GList *list, EggRecentViewBonobo *view)
324 {
325         if (list != NULL)
326                 egg_recent_view_bonobo_set_list (view, list);
327         else
328                 egg_recent_view_bonobo_clear (view);
329 }
330
331
332 static EggRecentModel *
333 egg_recent_view_bonobo_get_model (EggRecentView *view_parent)
334 {
335         EggRecentViewBonobo *view;
336         
337         g_return_val_if_fail (view_parent, NULL);
338         view = EGG_RECENT_VIEW_BONOBO (view_parent);
339         
340         return view->model;
341 }
342
343 static void
344 egg_recent_view_bonobo_set_model (EggRecentView *view_parent, EggRecentModel *model)
345 {
346         EggRecentViewBonobo *view;
347         
348         g_return_if_fail (view_parent);
349         view = EGG_RECENT_VIEW_BONOBO (view_parent);
350         
351         if (view->model)
352                 g_signal_handler_disconnect (G_OBJECT (view->model),
353                                              view->changed_cb_id);
354         
355         view->model = model;
356         g_object_ref (view->model);
357         view->changed_cb_id = g_signal_connect_object (G_OBJECT (model),
358                                                 "changed",
359                                                 G_CALLBACK (model_changed_cb),
360                                                 view, 0);
361
362         egg_recent_model_changed (view->model);
363 }
364
365 static void
366 egg_recent_view_bonobo_set_property (GObject *object,
367                            guint prop_id,
368                            const GValue *value,
369                            GParamSpec *pspec)
370 {
371         EggRecentViewBonobo *view = EGG_RECENT_VIEW_BONOBO (object);
372
373         switch (prop_id)
374         {
375                 case PROP_UI_COMPONENT:
376                         egg_recent_view_bonobo_set_ui_component (EGG_RECENT_VIEW_BONOBO (view),
377                                                        BONOBO_UI_COMPONENT (g_value_get_object (value)));
378                 break;
379                 case PROP_MENU_PATH:
380                         view->path = g_strdup (g_value_get_string (value));
381                 break;
382                 case PROP_SHOW_ICONS:
383                         egg_recent_view_bonobo_show_icons (view,
384                                                 g_value_get_boolean (value));
385                 default:
386                 case PROP_SHOW_NUMBERS:
387                         egg_recent_view_bonobo_show_numbers (view,
388                                                 g_value_get_boolean (value));
389                 break;
390                 break;
391         }
392 }
393
394 static void
395 egg_recent_view_bonobo_get_property (GObject *object,
396                            guint prop_id,
397                            GValue *value,
398                            GParamSpec *pspec)
399 {
400         EggRecentViewBonobo *view = EGG_RECENT_VIEW_BONOBO (object);
401
402         switch (prop_id)
403         {
404                 case PROP_UI_COMPONENT:
405                         g_value_set_pointer (value, view->uic);
406                 break;
407                 case PROP_MENU_PATH:
408                         g_value_set_string (value, g_strdup (view->path));
409                 break;
410                 case PROP_SHOW_ICONS:
411                         g_value_set_boolean (value, view->show_icons);
412                 break;
413                 case PROP_SHOW_NUMBERS:
414                         g_value_set_boolean (value, view->show_numbers);
415                 break;
416                 default:
417                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
418         }
419 }
420
421 static void
422 egg_recent_view_bonobo_finalize (GObject *object)
423 {
424         EggRecentViewBonobo *view = EGG_RECENT_VIEW_BONOBO (object);
425
426         g_free (view->path);
427         g_free (view->uid);
428
429         g_object_unref (view->model);
430         g_object_unref (view->uic);
431 #ifndef USE_STABLE_LIBGNOMEUI
432         g_object_unref (view->theme);
433 #endif
434         g_object_unref (view->client);
435 }
436
437 static void
438 egg_recent_view_bonobo_class_init (EggRecentViewBonoboClass * klass)
439 {
440         GObjectClass *object_class;
441
442         
443         object_class = G_OBJECT_CLASS (klass);
444
445         object_class->set_property = egg_recent_view_bonobo_set_property;
446         object_class->get_property = egg_recent_view_bonobo_get_property;
447         object_class->finalize     = egg_recent_view_bonobo_finalize;
448
449         egg_recent_view_bonobo_signals[ACTIVATE] = g_signal_new ("activate",
450                         G_OBJECT_CLASS_TYPE (object_class),
451                         G_SIGNAL_RUN_LAST,
452                         G_STRUCT_OFFSET (EggRecentViewBonoboClass, activate),
453                         NULL, NULL,
454                         g_cclosure_marshal_VOID__BOXED,
455                         G_TYPE_NONE, 1,
456                         EGG_TYPE_RECENT_ITEM);
457
458         g_object_class_install_property (object_class,
459                                          PROP_UI_COMPONENT,
460                                          g_param_spec_object ("ui-component",
461                                            "UI Component",
462                                            "BonoboUIComponent for menus.",
463                                            bonobo_ui_component_get_type(),
464                                            G_PARAM_READWRITE));
465
466         g_object_class_install_property (object_class,
467                                          PROP_MENU_PATH,
468                                          g_param_spec_string ("ui-path",
469                                            "Path",
470                                            "The path to put the menu items.",
471                                            "/menus/File/EggRecentDocuments",
472                                            G_PARAM_READWRITE));
473
474         g_object_class_install_property (object_class,
475                                          PROP_SHOW_ICONS,
476                                          g_param_spec_boolean ("show-icons",
477                                            "Show Icons",
478                                            "Whether or not to show icons",
479                                            FALSE,
480                                            G_PARAM_READWRITE));
481
482         g_object_class_install_property (object_class,
483                                          PROP_SHOW_NUMBERS,
484                                          g_param_spec_boolean ("show-numbers",
485                                            "Show Numbers",
486                                            "Whether or not to show numbers",
487                                            TRUE,
488                                            G_PARAM_READWRITE));
489
490
491
492         klass->activate = NULL;
493 }
494
495 static void
496 egg_recent_view_init (EggRecentViewClass *iface)
497 {
498         iface->do_get_model = egg_recent_view_bonobo_get_model;
499         iface->do_set_model = egg_recent_view_bonobo_set_model;
500 }
501
502 static void
503 show_menus_changed_cb (GConfClient *client,
504                        guint cnxn_id,
505                        GConfEntry *entry,
506                        EggRecentViewBonobo *view)
507 {
508         GConfValue *value;
509
510         value = gconf_entry_get_value (entry);
511
512         g_return_if_fail (value->type == GCONF_VALUE_BOOL);
513
514         egg_recent_view_bonobo_show_icons (view,
515                                 gconf_value_get_bool (value));
516
517 }
518
519 #ifndef USE_STABLE_LIBGNOMEUI
520 static void
521 theme_changed_cb (GnomeIconTheme *theme, EggRecentViewBonobo *view)
522 {
523         if (view->model != NULL)
524                 egg_recent_model_changed (view->model);
525 }
526 #endif
527
528 static void
529 egg_recent_view_bonobo_init (EggRecentViewBonobo *view)
530 {
531         view->uid = egg_recent_util_get_unique_id ();
532 #ifndef USE_STABLE_LIBGNOMEUI
533         view->theme = gnome_icon_theme_new ();
534         gnome_icon_theme_set_allow_svg (view->theme, TRUE);
535         g_signal_connect_object (view->theme, "changed",
536                                  G_CALLBACK (theme_changed_cb), view, 0);
537 #endif
538
539         view->client = gconf_client_get_default ();
540         view->show_icons =
541                 gconf_client_get_bool (view->client,
542                         "/desktop/gnome/interface/menus_have_icons",
543                         NULL);
544
545         gconf_client_add_dir (view->client, "/desktop/gnome/interface",
546                               GCONF_CLIENT_PRELOAD_NONE,
547                               NULL);
548         gconf_client_notify_add (view->client,
549                         "/desktop/gnome/interface/menus_have_icons",
550                         (GConfClientNotifyFunc)show_menus_changed_cb,
551                         view, NULL, NULL);
552
553         view->tooltip_func = NULL;
554         view->tooltip_func_data = NULL;
555
556         view->icon_size = GTK_ICON_SIZE_MENU;
557 }
558
559 void
560 egg_recent_view_bonobo_set_icon_size (EggRecentViewBonobo *view,
561                                       GtkIconSize icon_size)
562 {
563         if (view->icon_size != icon_size) {
564                 view->icon_size = icon_size;
565                 egg_recent_model_changed (view->model);
566         } else {
567                 view->icon_size = icon_size;
568         }
569 }
570                                                                               
571 GtkIconSize
572 egg_recent_view_bonobo_get_icon_size (EggRecentViewBonobo *view)
573 {
574         return view->icon_size;
575 }
576
577 void
578 egg_recent_view_bonobo_show_icons (EggRecentViewBonobo *view, gboolean show)
579 {
580         view->show_icons = show;
581
582         if (view->model)
583                 egg_recent_model_changed (view->model);
584 }
585
586 void
587 egg_recent_view_bonobo_show_numbers (EggRecentViewBonobo *view, gboolean show)
588 {
589         view->show_numbers = show;
590
591         if (view->model)
592                 egg_recent_model_changed (view->model);
593 }
594
595 void
596 egg_recent_view_bonobo_set_ui_component (EggRecentViewBonobo *view, BonoboUIComponent *uic)
597 {
598         g_return_if_fail (view);
599         g_return_if_fail (uic);
600
601         view->uic = uic;
602
603         g_object_ref (view->uic);
604 }
605
606 void
607 egg_recent_view_bonobo_set_ui_path (EggRecentViewBonobo *view, const gchar *path)
608 {
609         g_return_if_fail (view);
610         g_return_if_fail (path);
611
612         view->path = g_strdup (path);
613 }
614
615 const BonoboUIComponent *
616 egg_recent_view_bonobo_get_ui_component (EggRecentViewBonobo *view)
617 {
618         g_return_val_if_fail (view, NULL);
619
620         return view->uic;
621 }
622
623 gchar *
624 egg_recent_view_bonobo_get_ui_path (EggRecentViewBonobo *view)
625 {
626         g_return_val_if_fail (view, NULL);
627
628         return g_strdup (view->path);
629 }
630
631 void
632 egg_recent_view_bonobo_set_tooltip_func (EggRecentViewBonobo *view,
633                                          EggRecentViewBonoboTooltipFunc func,
634                                          gpointer user_data)
635 {
636         view->tooltip_func = func;
637         view->tooltip_func_data = user_data;
638         
639         if (view->model)
640                 egg_recent_model_changed (view->model);
641 }
642
643 /**
644  * egg_recent_view_bonobo_new:
645  * @appname: The name of your application.
646  * @limit:  The maximum number of items allowed.
647  *
648  * This creates a new EggRecentViewBonobo object.
649  *
650  * Returns: a EggRecentViewBonobo object
651  */
652 EggRecentViewBonobo *
653 egg_recent_view_bonobo_new (BonoboUIComponent *uic, const gchar *path)
654 {
655         EggRecentViewBonobo *view;
656
657         g_return_val_if_fail (uic, NULL);
658         g_return_val_if_fail (path, NULL);
659
660         view = EGG_RECENT_VIEW_BONOBO (g_object_new (egg_recent_view_bonobo_get_type (),
661                                            "ui-path", path,
662                                            "ui-component", uic,
663                                            "show-icons", FALSE,
664                                            "show-numbers", TRUE, NULL));
665
666         g_return_val_if_fail (view, NULL);
667         
668         return view;
669 }
670
671 /**
672  * egg_recent_view_bonobo_get_type:
673  * @:
674  *
675  * This returns a GType representing a EggRecentViewBonobo object.
676  *
677  * Returns: a GType
678  */
679 GType
680 egg_recent_view_bonobo_get_type (void)
681 {
682         static GType egg_recent_view_bonobo_type = 0;
683
684         if(!egg_recent_view_bonobo_type) {
685                 static const GTypeInfo egg_recent_view_bonobo_info = {
686                         sizeof (EggRecentViewBonoboClass),
687                         NULL, /* base init */
688                         NULL, /* base finalize */
689                         (GClassInitFunc)egg_recent_view_bonobo_class_init, /* class init */
690                         NULL, /* class finalize */
691                         NULL, /* class data */
692                         sizeof (EggRecentViewBonobo),
693                         0,
694                         (GInstanceInitFunc) egg_recent_view_bonobo_init
695                 };
696
697                 static const GInterfaceInfo view_info =
698                 {
699                         (GInterfaceInitFunc) egg_recent_view_init,
700                         NULL,
701                         NULL
702                 };
703
704                 egg_recent_view_bonobo_type = g_type_register_static (G_TYPE_OBJECT,
705                                                         "EggRecentViewBonobo",
706                                                         &egg_recent_view_bonobo_info, 0);
707                 g_type_add_interface_static (egg_recent_view_bonobo_type,
708                                              EGG_TYPE_RECENT_VIEW,
709                                              &view_info);
710         }
711
712         return egg_recent_view_bonobo_type;
713 }
714