1 /* gdict-source-dialog.c - source dialog
2  *
3  * This file is part of GNOME Dictionary
4  *
5  * Copyright (C) 2005 Emmanuele Bassi
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include "config.h"
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <time.h>
27 #include <sys/types.h>
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31 
32 #include <glib/gi18n.h>
33 
34 #include <gio/gio.h>
35 
36 #include "gdict-source-dialog.h"
37 #include "gdict-common.h"
38 
39 #define GDICT_SOURCE_UI 	"/org/gnome/Dictionary/gdict-source-dialog.ui"
40 
41 /*********************
42  * GdictSourceDialog *
43  *********************/
44 
45 struct _GdictSourceDialog
46 {
47   GtkDialog parent_instance;
48 
49   GSettings *settings;
50 
51   GdictSourceLoader *loader;
52   GdictSource *source;
53   gchar *source_name;
54   GdictContext *context;
55 
56   GdictSourceDialogAction action;
57 
58   GdictSourceTransport transport;
59 
60   GtkWidget *hostname_label;
61   GtkWidget *hostname_entry;
62   GtkWidget *port_label;
63   GtkWidget *port_entry;
64 
65   GtkWidget *description_label;
66   GtkWidget *description_entry;
67 
68   GtkWidget *add_button;
69   GtkWidget *close_button;
70   GtkWidget *cancel_button;
71   GtkWidget *help_button;
72 
73   GtkWidget *db_vbox;
74   GtkWidget *db_chooser;
75   GtkWidget *strat_vbox;
76   GtkWidget *strat_chooser;
77 
78   GtkWidget *transport_combo;
79 };
80 
81 struct _GdictSourceDialogClass
82 {
83   GtkDialogClass parent_class;
84 };
85 
86 enum
87 {
88   PROP_0,
89 
90   PROP_SOURCE_LOADER,
91   PROP_SOURCE_NAME,
92   PROP_ACTION
93 };
94 
G_DEFINE_TYPE(GdictSourceDialog,gdict_source_dialog,GTK_TYPE_DIALOG)95 G_DEFINE_TYPE (GdictSourceDialog, gdict_source_dialog, GTK_TYPE_DIALOG)
96 
97 static void
98 set_source_loader (GdictSourceDialog *dialog,
99 		   GdictSourceLoader *loader)
100 {
101   if (dialog->loader)
102     g_object_unref (dialog->loader);
103 
104   dialog->loader = g_object_ref (loader);
105 }
106 
107 static void
on_transport_changed(GtkWidget * widget,gpointer user_data)108 on_transport_changed (GtkWidget *widget,
109                       gpointer   user_data)
110 {
111   GdictSourceDialog *dialog = user_data;
112   GdictSourceTransport transport;
113 
114   transport = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
115   if (transport == dialog->transport)
116     return;
117 
118   /* Hide everything by default */
119   gtk_widget_hide (dialog->hostname_label);
120   gtk_widget_hide (dialog->hostname_entry);
121   gtk_widget_hide (dialog->port_label);
122   gtk_widget_hide (dialog->port_entry);
123 
124   if (dialog->action == GDICT_SOURCE_DIALOG_CREATE)
125     {
126       gtk_widget_set_sensitive (dialog->add_button, FALSE);
127       dialog->transport = GDICT_SOURCE_TRANSPORT_INVALID;
128     }
129 
130   /* Then show what's needed depending on the transport */
131   switch (transport)
132     {
133     case GDICT_SOURCE_TRANSPORT_DICTD:
134       gtk_widget_show (dialog->hostname_label);
135       gtk_widget_show (dialog->hostname_entry);
136       gtk_widget_show (dialog->port_label);
137       gtk_widget_show (dialog->port_entry);
138 
139       if (dialog->action == GDICT_SOURCE_DIALOG_CREATE)
140         {
141           gtk_widget_set_sensitive (dialog->add_button, TRUE);
142           dialog->transport = GDICT_SOURCE_TRANSPORT_DICTD;
143         }
144       break;
145 
146     default:
147       break;
148     }
149 }
150 
151 static void
set_transport_settings(GdictSourceDialog * dialog)152 set_transport_settings (GdictSourceDialog *dialog)
153 {
154   switch (dialog->transport)
155     {
156     case GDICT_SOURCE_TRANSPORT_DICTD:
157       {
158         GdictClientContext *context;
159         const gchar *hostname;
160         gchar *port_str;
161         guint port;
162 
163         context = GDICT_CLIENT_CONTEXT (dialog->context);
164         hostname = gdict_client_context_get_hostname (context);
165         port = gdict_client_context_get_port (context);
166         port_str = g_strdup_printf ("%d", port);
167 
168         gtk_entry_set_text (GTK_ENTRY (dialog->hostname_entry), hostname);
169         gtk_entry_set_text (GTK_ENTRY (dialog->port_entry), port_str);
170 
171         gtk_widget_show (dialog->hostname_label);
172         gtk_widget_show (dialog->hostname_entry);
173         gtk_widget_show (dialog->port_label);
174         gtk_widget_show (dialog->port_entry);
175 
176         g_free (port_str);
177       }
178       break;
179 
180     default:
181       break;
182     }
183 }
184 
185 static void
update_dialog_ui(GdictSourceDialog * dialog)186 update_dialog_ui (GdictSourceDialog *dialog)
187 {
188   GdictSource *source;
189 
190   /* TODO - add code to update the contents of the dialog depending
191    * on the action; if we are in _CREATE, no action is needed
192    */
193   switch (dialog->action)
194     {
195     case GDICT_SOURCE_DIALOG_VIEW:
196     case GDICT_SOURCE_DIALOG_EDIT:
197       if (!dialog->source_name)
198 	{
199           g_warning ("Attempting to retrieve source, but no "
200 		     "source name has been defined.  Aborting...");
201 	  return;
202 	}
203 
204       source = gdict_source_loader_get_source (dialog->loader, dialog->source_name);
205       if (!source)
206 	{
207           g_warning ("Attempting to retrieve source, but no "
208 		     "source named `%s' was found.  Aborting...",
209 		     dialog->source_name);
210 	  return;
211 	}
212 
213       g_object_ref (source);
214 
215       dialog->source = g_object_ref (source);
216       gtk_entry_set_text (GTK_ENTRY (dialog->description_entry), gdict_source_get_description (source));
217       dialog->transport = gdict_source_get_transport (source);
218       gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->transport_combo), (gint) dialog->transport);
219 
220       /* set the context for the database and strategy choosers */
221       dialog->context = gdict_source_get_context (source);
222       if (!dialog->context)
223         {
224           g_warning ("Attempting to retrieve the context, but "
225                      "none was found for source `%s'.",
226                      dialog->source_name);
227           return;
228         }
229 
230       set_transport_settings (dialog);
231 
232       gdict_database_chooser_set_context (GDICT_DATABASE_CHOOSER (dialog->db_chooser),
233                                           dialog->context);
234       gdict_database_chooser_refresh (GDICT_DATABASE_CHOOSER (dialog->db_chooser));
235       gdict_strategy_chooser_set_context (GDICT_STRATEGY_CHOOSER (dialog->strat_chooser),
236                                           dialog->context);
237       gdict_strategy_chooser_refresh (GDICT_STRATEGY_CHOOSER (dialog->strat_chooser));
238       break;
239 
240     case GDICT_SOURCE_DIALOG_CREATE:
241       /* DICTD transport is default */
242       gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->transport_combo), 0);
243       g_signal_emit_by_name (dialog->transport_combo, "changed");
244       break;
245 
246     default:
247       g_assert_not_reached ();
248       break;
249     }
250 }
251 
252 static void
build_new_source(GdictSourceDialog * dialog)253 build_new_source (GdictSourceDialog *dialog)
254 {
255   GdictSource *source;
256   gchar *name, *text;
257   GdictSourceTransport transport;
258   gchar *data;
259   gsize length;
260   GError *error;
261   gchar *filename;
262   gchar *config_dir;
263   GdictDatabaseChooser *db_chooser;
264   GdictStrategyChooser *strat_chooser;
265 
266   source = gdict_source_new ();
267 
268   /* use the timestamp and the pid to get a unique name */
269   name = g_strdup_printf ("source-%lu-%u",
270                           (gulong) time (NULL),
271                           (guint) getpid ());
272   gdict_source_set_name (source, name);
273   g_free (name);
274 
275   gdict_source_set_description (source, gtk_entry_get_text (GTK_ENTRY (dialog->description_entry)));
276 
277   db_chooser = GDICT_DATABASE_CHOOSER (dialog->db_chooser);
278   text = gdict_database_chooser_get_current_database (db_chooser);
279   gdict_source_set_database (source, text);
280   g_free (text);
281 
282   strat_chooser = GDICT_STRATEGY_CHOOSER (dialog->strat_chooser);
283   text = gdict_strategy_chooser_get_current_strategy (strat_chooser);
284   gdict_source_set_strategy (source, text);
285   g_free (text);
286 
287   /* get the selected transport id */
288   transport = dialog->transport;
289   switch (transport)
290     {
291     case GDICT_SOURCE_TRANSPORT_DICTD:
292       {
293         const char *host = gtk_entry_get_text (GTK_ENTRY (dialog->hostname_entry));
294         const char *port = gtk_entry_get_text (GTK_ENTRY (dialog->port_entry));
295 
296         gdict_source_set_transport (source, GDICT_SOURCE_TRANSPORT_DICTD,
297                                     "hostname", host,
298                                     "port", atoi (port),
299                                     NULL);
300       }
301       break;
302 
303     case GDICT_SOURCE_TRANSPORT_INVALID:
304     default:
305       g_warning ("Invalid transport");
306       return;
307     }
308 
309   error = NULL;
310   data = gdict_source_to_data (source, &length, &error);
311   if (error != NULL)
312     {
313       gdict_show_gerror_dialog (GTK_WINDOW (dialog),
314 				_("Unable to create a source file"),
315 				error);
316 
317       g_object_unref (source);
318       return;
319     }
320 
321   config_dir = gdict_get_config_dir ();
322   name = g_strconcat (gdict_source_get_name (source), ".desktop", NULL);
323   filename = g_build_filename (config_dir, name, NULL);
324   g_free (config_dir);
325   g_free (name);
326 
327   g_debug ("Saving new source '%s' (%s) at '%s'",
328            gdict_source_get_description (source),
329            gdict_source_get_name (source),
330            filename);
331 
332   g_file_set_contents (filename, data, length, &error);
333 
334   if (error != NULL)
335     gdict_show_gerror_dialog (GTK_WINDOW (dialog),
336        			      _("Unable to save source file"),
337        			      error);
338 
339   g_free (filename);
340   g_free (data);
341   g_object_unref (source);
342 }
343 
344 static void
save_source(GdictSourceDialog * dialog)345 save_source (GdictSourceDialog *dialog)
346 {
347   GdictSource *source;
348   GdictDatabaseChooser *db_chooser;
349   GdictStrategyChooser *strat_chooser;
350   gchar *name, *text;
351   GdictSourceTransport transport;
352   gchar *data;
353   gsize length;
354   GError *error;
355   gchar *filename;
356   gchar *config_dir;
357 
358   source = gdict_source_loader_get_source (dialog->loader, dialog->source_name);
359   if (!source)
360     {
361       g_warning ("Attempting to save source `%s', but no "
362 		 "source for that name was found.",
363 		 dialog->source_name);
364 
365       return;
366     }
367 
368   gdict_source_set_description (source, gtk_entry_get_text (GTK_ENTRY (dialog->description_entry)));
369 
370   db_chooser = GDICT_DATABASE_CHOOSER (dialog->db_chooser);
371   text = gdict_database_chooser_get_current_database (db_chooser);
372   gdict_source_set_database (source, text);
373   g_free (text);
374 
375   strat_chooser = GDICT_STRATEGY_CHOOSER (dialog->strat_chooser);
376   text = gdict_strategy_chooser_get_current_strategy (strat_chooser);
377   gdict_source_set_strategy (source, text);
378   g_free (text);
379 
380 
381   /* get the selected transport id */
382   transport = dialog->transport;
383   switch (transport)
384     {
385     case GDICT_SOURCE_TRANSPORT_DICTD:
386       {
387         const char *host = gtk_entry_get_text (GTK_ENTRY (dialog->hostname_entry));
388         const char *port = gtk_entry_get_text (GTK_ENTRY (dialog->port_entry));
389 
390         gdict_source_set_transport (source, GDICT_SOURCE_TRANSPORT_DICTD,
391                                     "hostname", host,
392                                     "port", atoi (port),
393                                     NULL);
394       }
395       break;
396 
397     case GDICT_SOURCE_TRANSPORT_INVALID:
398     default:
399       g_warning ("Invalid transport");
400       return;
401     }
402 
403   error = NULL;
404   data = gdict_source_to_data (source, &length, &error);
405   if (error)
406     {
407       gdict_show_gerror_dialog (GTK_WINDOW (dialog),
408 			 	_("Unable to create a source file"),
409 			 	error);
410 
411       g_object_unref (source);
412       return;
413     }
414 
415   g_object_get (source, "filename", &filename, NULL);
416   if (!filename)
417     {
418       config_dir = gdict_get_config_dir();
419       name = g_strconcat (gdict_source_get_name (source), ".desktop", NULL);
420       filename = g_build_filename (config_dir, name, NULL);
421       g_free (config_dir);
422       g_free (name);
423     }
424 
425   g_file_set_contents (filename, data, length, &error);
426   if (error)
427     gdict_show_gerror_dialog (GTK_WINDOW (dialog),
428        			      _("Unable to save source file"),
429        			      error);
430 
431   g_free (filename);
432   g_free (data);
433   g_object_unref (source);
434 }
435 
436 static void
on_dialog_response(GtkDialog * dialog,gint response_id,gpointer user_data)437 on_dialog_response (GtkDialog *dialog,
438                     gint       response_id,
439                     gpointer   user_data)
440 {
441   GError *err = NULL;
442 
443   switch (response_id)
444     {
445     case GTK_RESPONSE_ACCEPT:
446       build_new_source (GDICT_SOURCE_DIALOG (dialog));
447       break;
448 
449     case GTK_RESPONSE_HELP:
450 #if GTK_CHECK_VERSION (3, 22, 0)
451       gtk_show_uri_on_window (GTK_WINDOW (dialog),
452                               "help:gnome-dictionary/gnome-dictionary-add-source",
453                               gtk_get_current_event_time (), &err);
454 #else
455       gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (dialog)),
456                     "help:gnome-dictionary/gnome-dictionary-add-source",
457                     gtk_get_current_event_time (), &err);
458 #endif
459 
460       if (err)
461         {
462           gdict_show_gerror_dialog (GTK_WINDOW (dialog),
463           			    _("There was an error while displaying help"),
464           		 	    err);
465           g_error_free (err);
466         }
467 
468       /* we don't want the dialog to close itself */
469       g_signal_stop_emission_by_name (dialog, "response");
470       break;
471 
472     case GTK_RESPONSE_CLOSE:
473       save_source (GDICT_SOURCE_DIALOG (dialog));
474       break;
475 
476     case GTK_RESPONSE_CANCEL:
477       break;
478 
479     default:
480       break;
481     }
482 }
483 
484 static void
gdict_source_dialog_finalize(GObject * object)485 gdict_source_dialog_finalize (GObject *object)
486 {
487   GdictSourceDialog *dialog = GDICT_SOURCE_DIALOG (object);
488 
489   g_clear_object (&dialog->settings);
490   g_clear_object (&dialog->source);
491   g_clear_object (&dialog->loader);
492 
493   g_free (dialog->source_name);
494 
495   G_OBJECT_CLASS (gdict_source_dialog_parent_class)->finalize (object);
496 }
497 
498 static void
gdict_source_dialog_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)499 gdict_source_dialog_set_property (GObject      *object,
500 				  guint         prop_id,
501 				  const GValue *value,
502 				  GParamSpec   *pspec)
503 {
504   GdictSourceDialog *dialog = GDICT_SOURCE_DIALOG (object);
505 
506   switch (prop_id)
507     {
508     case PROP_SOURCE_LOADER:
509       set_source_loader (dialog, g_value_get_object (value));
510       break;
511 
512     case PROP_SOURCE_NAME:
513       g_free (dialog->source_name);
514       dialog->source_name = g_strdup (g_value_get_string (value));
515       break;
516 
517     case PROP_ACTION:
518       dialog->action = (GdictSourceDialogAction) g_value_get_int (value);
519       break;
520 
521     default:
522       break;
523     }
524 }
525 
526 static void
gdict_source_dialog_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)527 gdict_source_dialog_get_property (GObject    *object,
528 				  guint       prop_id,
529 				  GValue     *value,
530 				  GParamSpec *pspec)
531 {
532   GdictSourceDialog *dialog = GDICT_SOURCE_DIALOG (object);
533 
534   switch (prop_id)
535     {
536     case PROP_SOURCE_LOADER:
537       g_value_set_object (value, dialog->loader);
538       break;
539 
540     case PROP_SOURCE_NAME:
541       g_value_set_string (value, dialog->source_name);
542       break;
543 
544     case PROP_ACTION:
545       g_value_set_int (value, dialog->action);
546       break;
547 
548     default:
549       break;
550     }
551 }
552 
553 static void
gdict_source_dialog_constructed(GObject * object)554 gdict_source_dialog_constructed (GObject *object)
555 {
556   GdictSourceDialog *dialog = GDICT_SOURCE_DIALOG (object);
557 
558   /* the UI changes depending on the action that the source dialog
559    * should perform
560    */
561   switch (dialog->action)
562     {
563     case GDICT_SOURCE_DIALOG_VIEW:
564       /* disable every editable widget */
565       gtk_editable_set_editable (GTK_EDITABLE (dialog->description_entry), FALSE);
566       gtk_editable_set_editable (GTK_EDITABLE (dialog->hostname_entry), FALSE);
567       gtk_editable_set_editable (GTK_EDITABLE (dialog->port_entry), FALSE);
568       gtk_widget_set_sensitive (dialog->transport_combo, FALSE);
569 
570       /* we just allow closing the dialog */
571       dialog->close_button = gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Close"), GTK_RESPONSE_CANCEL);
572       break;
573 
574     case GDICT_SOURCE_DIALOG_CREATE:
575       dialog->cancel_button = gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Cancel"), GTK_RESPONSE_CANCEL);
576       dialog->add_button = gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Add"), GTK_RESPONSE_ACCEPT);
577       /* the "add" button sensitivity is controlled by the transport_combo
578        * since it's the only setting that makes a source usable.
579        */
580       gtk_widget_set_sensitive (dialog->add_button, FALSE);
581       break;
582 
583     case GDICT_SOURCE_DIALOG_EDIT:
584       dialog->cancel_button = gtk_dialog_add_button (GTK_DIALOG (dialog), _("C_ancel"), GTK_RESPONSE_CANCEL);
585       dialog->close_button = gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Close"), GTK_RESPONSE_CLOSE);
586       break;
587 
588     default:
589       g_assert_not_reached ();
590       break;
591     }
592 
593   /* this will take care of updating the contents of the dialog
594    * based on the action
595    */
596   update_dialog_ui (dialog);
597 }
598 
599 static void
gdict_source_dialog_class_init(GdictSourceDialogClass * klass)600 gdict_source_dialog_class_init (GdictSourceDialogClass *klass)
601 {
602   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
603   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
604 
605   gobject_class->constructed = gdict_source_dialog_constructed;
606   gobject_class->set_property = gdict_source_dialog_set_property;
607   gobject_class->get_property = gdict_source_dialog_get_property;
608   gobject_class->finalize = gdict_source_dialog_finalize;
609 
610   g_object_class_install_property (gobject_class,
611   				   PROP_SOURCE_LOADER,
612   				   g_param_spec_object ("source-loader",
613   				   			"Source Loader",
614   				   			"The GdictSourceLoader used by the application",
615   				   			GDICT_TYPE_SOURCE_LOADER,
616   				   			G_PARAM_READWRITE |
617                                                         G_PARAM_CONSTRUCT_ONLY |
618                                                         G_PARAM_STATIC_STRINGS));
619   g_object_class_install_property (gobject_class,
620   				   PROP_SOURCE_NAME,
621   				   g_param_spec_string ("source-name",
622   				   			"Source Name",
623   				   			"The source name",
624   				   			NULL,
625                                                         G_PARAM_READWRITE |
626                                                         G_PARAM_CONSTRUCT_ONLY |
627                                                         G_PARAM_STATIC_STRINGS));
628   g_object_class_install_property (gobject_class,
629   				   PROP_ACTION,
630   				   g_param_spec_int ("action",
631   				   		     "Action",
632   				   		     "The action the source dialog should perform",
633   				   		     -1,
634   				   		     GDICT_SOURCE_DIALOG_EDIT,
635   				   		     GDICT_SOURCE_DIALOG_VIEW,
636                                                      G_PARAM_READWRITE |
637                                                      G_PARAM_CONSTRUCT_ONLY |
638                                                      G_PARAM_STATIC_STRINGS));
639 
640   gtk_widget_class_set_template_from_resource (widget_class, GDICT_SOURCE_UI);
641 
642   gtk_widget_class_bind_template_child (widget_class, GdictSourceDialog, transport_combo);
643   gtk_widget_class_bind_template_child (widget_class, GdictSourceDialog, hostname_label);
644   gtk_widget_class_bind_template_child (widget_class, GdictSourceDialog, hostname_entry);
645   gtk_widget_class_bind_template_child (widget_class, GdictSourceDialog, port_label);
646   gtk_widget_class_bind_template_child (widget_class, GdictSourceDialog, port_entry);
647   gtk_widget_class_bind_template_child (widget_class, GdictSourceDialog, description_label);
648   gtk_widget_class_bind_template_child (widget_class, GdictSourceDialog, description_entry);
649   gtk_widget_class_bind_template_child (widget_class, GdictSourceDialog, db_vbox);
650   gtk_widget_class_bind_template_child (widget_class, GdictSourceDialog, strat_vbox);
651 
652   gtk_widget_class_bind_template_callback (widget_class, on_dialog_response);
653   gtk_widget_class_bind_template_callback (widget_class, on_transport_changed);
654 }
655 
656 static void
gdict_source_dialog_init(GdictSourceDialog * dialog)657 gdict_source_dialog_init (GdictSourceDialog *dialog)
658 {
659   gtk_widget_init_template (GTK_WIDGET (dialog));
660 
661   gtk_widget_set_size_request (GTK_WIDGET (dialog), 400, 300);
662 
663   dialog->transport = GDICT_SOURCE_TRANSPORT_INVALID;
664 
665   /* The help button is always visible */
666   dialog->help_button = gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Help"), GTK_RESPONSE_HELP);
667 
668   /* Add our custom widgets */
669   dialog->db_chooser = gdict_database_chooser_new ();
670   gtk_box_pack_start (GTK_BOX (dialog->db_vbox), dialog->db_chooser, TRUE, TRUE, 0);
671   gtk_widget_show (dialog->db_chooser);
672 
673   dialog->strat_chooser = gdict_strategy_chooser_new ();
674   gtk_box_pack_start (GTK_BOX (dialog->strat_vbox), dialog->strat_chooser, TRUE, TRUE, 0);
675   gtk_widget_show (dialog->strat_chooser);
676 }
677 
678 GtkWidget *
gdict_source_dialog_new(GtkWindow * parent,const gchar * title,GdictSourceDialogAction action,GdictSourceLoader * loader,const gchar * source_name)679 gdict_source_dialog_new (GtkWindow               *parent,
680 			 const gchar             *title,
681 			 GdictSourceDialogAction  action,
682 			 GdictSourceLoader       *loader,
683 			 const gchar             *source_name)
684 {
685   GtkWidget *retval;
686 
687   g_return_val_if_fail ((parent == NULL || GTK_IS_WINDOW (parent)), NULL);
688   g_return_val_if_fail (GDICT_IS_SOURCE_LOADER (loader), NULL);
689 
690   retval = g_object_new (GDICT_TYPE_SOURCE_DIALOG,
691   			 "source-loader", loader,
692   			 "source-name", source_name,
693   			 "action", action,
694   			 "title", title,
695   			 NULL);
696 
697   if (parent)
698     {
699       gtk_window_set_transient_for (GTK_WINDOW (retval), parent);
700       gtk_window_set_destroy_with_parent (GTK_WINDOW (retval), TRUE);
701       gtk_window_set_screen (GTK_WINDOW (retval),
702                              gtk_widget_get_screen (GTK_WIDGET (parent)));
703     }
704 
705   return retval;
706 }
707