1 /*
2  * Copyright (C) 2011 Murray Cumming <murrayc@murrayc.com>
3  * Copyright (C) 2011 - 2012 Vivien Malerba <malerba@gnome-db.org>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18  */
19 
20 #include <glib/gi18n-lib.h>
21 #include <string.h>
22 #include "filter-editor.h"
23 #include <libgda-ui/gdaui-combo.h>
24 #include <libgda-ui/gdaui-data-selector.h>
25 
26 struct _FilterEditorPrivate {
27 	BrowserConnection *bcnc;
28 	GtkWidget *base_dn;
29 	GtkWidget *filter;
30 	GtkWidget *attributes;
31 	GtkWidget *scope;
32 
33 	GdaLdapSearchScope default_scope;
34 };
35 
36 static void filter_editor_class_init (FilterEditorClass *klass);
37 static void filter_editor_init       (FilterEditor *feditor, FilterEditorClass *klass);
38 static void filter_editor_dispose    (GObject *object);
39 
40 static GObjectClass *parent_class = NULL;
41 
42 /* signals */
43 enum {
44         ACTIVATE,
45 	LAST_SIGNAL
46 };
47 
48 gint filter_editor_signals [LAST_SIGNAL] = { 0 };
49 
50 /*
51  * FilterEditor class implementation
52  */
53 
54 static void
55 filter_editor_class_init (FilterEditorClass *klass)
56 {
57 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
58 
59 	parent_class = g_type_class_peek_parent (klass);
60 
61 	filter_editor_signals [ACTIVATE] =
62                 g_signal_new ("activate",
63                               G_TYPE_FROM_CLASS (object_class),
64                               G_SIGNAL_RUN_FIRST,
65                               G_STRUCT_OFFSET (FilterEditorClass, activate),
66                               NULL, NULL,
67                               g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
68 	klass->activate = NULL;
69 	object_class->dispose = filter_editor_dispose;
70 }
71 
72 static void
73 filter_editor_init (FilterEditor *feditor, G_GNUC_UNUSED FilterEditorClass *klass)
74 {
75 	feditor->priv = g_new0 (FilterEditorPrivate, 1);
76 	feditor->priv->bcnc = NULL;
77 	feditor->priv->default_scope = GDA_LDAP_SEARCH_SUBTREE;
78 
79 	gtk_orientable_set_orientation (GTK_ORIENTABLE (feditor), GTK_ORIENTATION_VERTICAL);
80 }
81 
82 static void
83 filter_editor_dispose (GObject *object)
84 {
85 	FilterEditor *feditor = (FilterEditor *) object;
86 
87 	/* free memory */
88 	if (feditor->priv) {
89 		if (feditor->priv->bcnc)
90 			g_object_unref (feditor->priv->bcnc);
91 		g_free (feditor->priv);
92 		feditor->priv = NULL;
93 	}
94 
95 	parent_class->dispose (object);
96 }
97 
98 GType
99 filter_editor_get_type (void)
100 {
101 	static GType type = 0;
102 
103 	if (G_UNLIKELY (type == 0)) {
104 		static const GTypeInfo info = {
105 			sizeof (FilterEditorClass),
106 			(GBaseInitFunc) NULL,
107 			(GBaseFinalizeFunc) NULL,
108 			(GClassInitFunc) filter_editor_class_init,
109 			NULL,
110 			NULL,
111 			sizeof (FilterEditor),
112 			0,
113 			(GInstanceInitFunc) filter_editor_init,
114 			0
115 		};
116 
117 		type = g_type_register_static (GTK_TYPE_BOX, "FilterEditor", &info, 0);
118 	}
119 	return type;
120 }
121 
122 static void
123 activated_cb (G_GNUC_UNUSED GtkEntry *entry, FilterEditor *feditor)
124 {
125 	g_signal_emit (feditor, filter_editor_signals [ACTIVATE], 0);
126 }
127 
128 /**
129  * filter_editor_new:
130  *
131  * Returns: a new #GtkWidget
132  */
133 GtkWidget *
134 filter_editor_new (BrowserConnection *bcnc)
135 {
136 	FilterEditor *feditor;
137 	GtkWidget *grid, *label, *entry;
138 	GdaDataModel *model;
139 	GList *values;
140 	GValue *v1, *v2;
141 	gfloat ya;
142 
143 	g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
144 
145 	feditor = FILTER_EDITOR (g_object_new (FILTER_EDITOR_TYPE, NULL));
146 	feditor->priv->bcnc = g_object_ref ((GObject*) bcnc);
147 
148 	grid = gtk_grid_new ();
149 	gtk_grid_set_column_spacing (GTK_GRID (grid), 5);
150 	gtk_box_pack_start (GTK_BOX (feditor), grid, TRUE, TRUE, 0);
151 
152 	label = gtk_label_new (_("Base DN:"));
153 	gtk_misc_get_alignment (GTK_MISC (label), NULL, &ya);
154 	gtk_misc_set_alignment (GTK_MISC (label), 0., ya);
155 	gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1);
156 	label = gtk_label_new (_("Filter expression:"));
157 	gtk_misc_get_alignment (GTK_MISC (label), NULL, &ya);
158 	gtk_misc_set_alignment (GTK_MISC (label), 0., ya);
159 	gtk_grid_attach (GTK_GRID (grid), label, 0, 1, 1, 1);
160 	label = gtk_label_new (_("Attributes to fetch:"));
161 	gtk_misc_get_alignment (GTK_MISC (label), NULL, &ya);
162 	gtk_misc_set_alignment (GTK_MISC (label), 0., ya);
163 	gtk_grid_attach (GTK_GRID (grid), label, 0, 2, 1, 1);
164 	label = gtk_label_new (_("Search scope:"));
165 	gtk_misc_get_alignment (GTK_MISC (label), NULL, &ya);
166 	gtk_misc_set_alignment (GTK_MISC (label), 0., ya);
167 	gtk_grid_attach (GTK_GRID (grid), label, 0, 3, 1, 1);
168 
169 	entry = gtk_entry_new ();
170 	gtk_grid_attach (GTK_GRID (grid), entry, 1, 0, 1, 1);
171 	feditor->priv->base_dn = entry;
172 	g_signal_connect (entry, "activate",
173 			  G_CALLBACK (activated_cb), feditor);
174 
175 	entry = gtk_entry_new ();
176 	gtk_grid_attach (GTK_GRID (grid), entry, 1, 1, 1, 1);
177 	feditor->priv->filter = entry;
178 	g_signal_connect (entry, "activate",
179 			  G_CALLBACK (activated_cb), feditor);
180 
181 	entry = gtk_entry_new ();
182 	gtk_grid_attach (GTK_GRID (grid), entry, 1, 2, 1, 1);
183 	feditor->priv->attributes = entry;
184 	g_signal_connect (entry, "activate",
185 			  G_CALLBACK (activated_cb), feditor);
186 
187 	model = gda_data_model_array_new_with_g_types (2, G_TYPE_INT, G_TYPE_STRING);
188 	g_value_set_string ((v1 = gda_value_new (G_TYPE_STRING)), "Base (search the base DN only)");
189 	values = g_list_prepend (NULL, v1);
190 	g_value_set_int ((v2 = gda_value_new (G_TYPE_INT)), GDA_LDAP_SEARCH_BASE);
191 	values = g_list_prepend (values, v2);
192 	g_assert (gda_data_model_append_values (model, values, NULL) >= 0);
193 	gda_value_free (v1);
194 	gda_value_free (v2);
195 
196 	g_value_set_string ((v1 = gda_value_new (G_TYPE_STRING)), "Onelevel (search immediate children of base DN only)");
197 	values = g_list_prepend (NULL, v1);
198 	g_value_set_int ((v2 = gda_value_new (G_TYPE_INT)), GDA_LDAP_SEARCH_ONELEVEL);
199 	values = g_list_prepend (values, v2);
200 	g_assert (gda_data_model_append_values (model, values, NULL) >= 0);
201 	gda_value_free (v1);
202 	gda_value_free (v2);
203 
204 	g_value_set_string ((v1 = gda_value_new (G_TYPE_STRING)), "Subtree (search of the base DN and the entire subtree below)");
205 	values = g_list_prepend (NULL, v1);
206 	g_value_set_int ((v2 = gda_value_new (G_TYPE_INT)), GDA_LDAP_SEARCH_SUBTREE);
207 	values = g_list_prepend (values, v2);
208 	g_assert (gda_data_model_append_values (model, values, NULL) >= 0);
209 	gda_value_free (v1);
210 	gda_value_free (v2);
211 
212 	gint cols[] = {1};
213 	entry = gdaui_combo_new_with_model (model, 1, cols);
214 	g_object_unref (model);
215 	gtk_grid_attach (GTK_GRID (grid), entry, 1, 3, 1, 1);
216 	feditor->priv->scope = entry;
217 	filter_editor_clear (feditor);
218 
219 	gtk_widget_show_all (grid);
220 	return (GtkWidget*) feditor;
221 }
222 
223 /**
224  * filter_editor_clear:
225  */
226 void
227 filter_editor_clear (FilterEditor *fedit)
228 {
229 	g_return_if_fail (IS_FILTER_EDITOR (fedit));
230 	filter_editor_set_settings (fedit, NULL, NULL, NULL, fedit->priv->default_scope);
231 }
232 
233 /**
234  * filter_editor_set_settings:
235  */
236 void
237 filter_editor_set_settings (FilterEditor *fedit,
238 			    const gchar *base_dn, const gchar *filter,
239 			    const gchar *attributes, GdaLdapSearchScope scope)
240 {
241 	g_return_if_fail (IS_FILTER_EDITOR (fedit));
242 
243 	gtk_entry_set_text (GTK_ENTRY (fedit->priv->base_dn), base_dn ? base_dn : "");
244 	gtk_entry_set_text (GTK_ENTRY (fedit->priv->filter), filter ? filter : "(cn=*)");
245 	gtk_entry_set_text (GTK_ENTRY (fedit->priv->attributes), attributes ? attributes : "cn");
246 	gdaui_data_selector_select_row (GDAUI_DATA_SELECTOR (fedit->priv->scope), scope - 1);
247 }
248 
249 /**
250  * filter_editor_get_settings:
251  */
252 void
253 filter_editor_get_settings (FilterEditor *fedit,
254 			    gchar **out_base_dn, gchar **out_filter,
255 			    gchar **out_attributes, GdaLdapSearchScope *out_scope)
256 {
257 	const gchar *tmp;
258 	g_return_if_fail (IS_FILTER_EDITOR (fedit));
259 	if (out_base_dn) {
260 		tmp = gtk_entry_get_text (GTK_ENTRY (fedit->priv->base_dn));
261 		*out_base_dn = tmp && *tmp ? g_strdup (tmp) : NULL;
262 	}
263 	if (out_filter) {
264 		tmp = gtk_entry_get_text (GTK_ENTRY (fedit->priv->filter));
265 		if (tmp && *tmp) {
266 			/* add surrounding parenthesis if not yet there */
267 			if (*tmp != '(') {
268 				gint len;
269 				len = strlen (tmp);
270 				if (tmp [len-1] != ')')
271 					*out_filter = g_strdup_printf ("(%s)", tmp);
272 				else
273 					*out_filter = g_strdup (tmp);/* may result in an error when executed */
274 			}
275 			else
276 				*out_filter = g_strdup (tmp);
277 
278 		}
279 		else
280 			*out_filter = NULL;
281 	}
282 	if (out_attributes) {
283 		tmp = gtk_entry_get_text (GTK_ENTRY (fedit->priv->attributes));
284 		*out_attributes = tmp && *tmp ? g_strdup (tmp) : NULL;
285 	}
286 	if (out_scope)
287 		*out_scope = gtk_combo_box_get_active (GTK_COMBO_BOX (fedit->priv->scope)) + 1;
288 }
289