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