1 /*
2  * Copyright (C) 2010 - 2011 Vivien Malerba <malerba@gnome-db.org>
3  * Copyright (C) 2011 Murray Cumming <murrayc@murrayc.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library 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 GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA  02110-1301, USA.
19  */
20 
21 #include <string.h>
22 #include "gdaui-entry-rt.h"
23 #include <libgda-ui/gdaui-rt-editor.h>
24 #include <libgda/gda-data-handler.h>
25 #include <libgda/gda-blob-op.h>
26 
27 /*
28  * Main static functions
29  */
30 static void gdaui_entry_rt_class_init (GdauiEntryRtClass * class);
31 static void gdaui_entry_rt_init (GdauiEntryRt * srv);
32 static void gdaui_entry_rt_dispose (GObject   * object);
33 static void gdaui_entry_rt_finalize (GObject   * object);
34 
file_load_cb(GtkWidget * button,BinMenu * menu)35 /* virtual functions */
36 static GtkWidget *create_entry (GdauiEntryWrapper *mgwrap);
37 static void       real_set_value (GdauiEntryWrapper *mgwrap, const GValue *value);
38 static GValue    *real_get_value (GdauiEntryWrapper *mgwrap);
39 static void       connect_signals(GdauiEntryWrapper *mgwrap, GCallback modify_cb, GCallback activate_cb);
40 static void       set_editable (GdauiEntryWrapper *mgwrap, gboolean editable);
41 
42 /* get a pointer to the parents to be able to call their destructor */
43 static GObjectClass  *parent_class = NULL;
44 
45 /* private structure */
46 struct _GdauiEntryRtPrivate
47 {
48 	GtkWidget     *view;
49 };
50 
51 
52 GType
53 gdaui_entry_rt_get_type (void)
54 {
55 	static GType type = 0;
56 
57 	if (G_UNLIKELY (type == 0)) {
58 		static const GTypeInfo info = {
59 			sizeof (GdauiEntryRtClass),
60 			(GBaseInitFunc) NULL,
61 			(GBaseFinalizeFunc) NULL,
62 			(GClassInitFunc) gdaui_entry_rt_class_init,
63 			NULL,
64 			NULL,
65 			sizeof (GdauiEntryRt),
66 			0,
67 			(GInstanceInitFunc) gdaui_entry_rt_init,
68 			0
69 		};
70 
71 		type = g_type_register_static (GDAUI_TYPE_ENTRY_WRAPPER, "GdauiEntryRt", &info, 0);
72 	}
73 	return type;
74 }
75 
76 static void
77 gdaui_entry_rt_class_init (GdauiEntryRtClass * class)
78 {
79 	GObjectClass   *object_class = G_OBJECT_CLASS (class);
80 
81 	parent_class = g_type_class_peek_parent (class);
82 
83 	object_class->dispose = gdaui_entry_rt_dispose;
84 	object_class->finalize = gdaui_entry_rt_finalize;
85 
86 	GDAUI_ENTRY_WRAPPER_CLASS (class)->create_entry = create_entry;
87 	GDAUI_ENTRY_WRAPPER_CLASS (class)->real_set_value = real_set_value;
88 	GDAUI_ENTRY_WRAPPER_CLASS (class)->real_get_value = real_get_value;
89 	GDAUI_ENTRY_WRAPPER_CLASS (class)->connect_signals = connect_signals;
90 	GDAUI_ENTRY_WRAPPER_CLASS (class)->set_editable = set_editable;
91 }
92 
93 static void
94 gdaui_entry_rt_init (GdauiEntryRt *gdaui_entry_rt)
95 {
96 	gdaui_entry_rt->priv = g_new0 (GdauiEntryRtPrivate, 1);
97 	gdaui_entry_rt->priv->view = NULL;
98 	gtk_widget_set_vexpand (GTK_WIDGET (gdaui_entry_rt), TRUE);
99 }
100 
101 /**
102  * gdaui_entry_rt_new
103  * @dh: the data handler to be used by the new widget
104  * @type: the requested data type (compatible with @dh)
file_save_cb(GtkWidget * button,BinMenu * menu)105  * @options: the options
106  *
107  * Creates a new widget which is mainly a GtkEntry
108  *
109  * Returns: the new widget
110  */
111 GtkWidget *
112 gdaui_entry_rt_new (GdaDataHandler *dh, GType type, G_GNUC_UNUSED const gchar *options)
113 {
114 	GObject *obj;
115 
116 	g_return_val_if_fail (dh && GDA_IS_DATA_HANDLER (dh), NULL);
117 	g_return_val_if_fail (gda_data_handler_accepts_g_type (dh, type), NULL);
118 
119 	obj = g_object_new (GDAUI_TYPE_ENTRY_RT, "handler", dh, NULL);
120 	gdaui_data_entry_set_value_type (GDAUI_DATA_ENTRY (obj), type);
121 
122 	return GTK_WIDGET (obj);
123 }
124 
125 
126 static void
127 gdaui_entry_rt_dispose (GObject   * object)
128 {
129 	GdauiEntryRt *gdaui_entry_rt;
130 
131 	g_return_if_fail (object != NULL);
132 	g_return_if_fail (GDAUI_IS_ENTRY_RT (object));
133 
134 	gdaui_entry_rt = GDAUI_ENTRY_RT (object);
135 	if (gdaui_entry_rt->priv) {
136 	}
137 
138 	/* parent class */
139 	parent_class->dispose (object);
140 }
141 
142 static void
143 gdaui_entry_rt_finalize (GObject   * object)
144 {
145 	GdauiEntryRt *gdaui_entry_rt;
146 
147 	g_return_if_fail (object != NULL);
148 	g_return_if_fail (GDAUI_IS_ENTRY_RT (object));
149 
150 	gdaui_entry_rt = GDAUI_ENTRY_RT (object);
151 	if (gdaui_entry_rt->priv) {
152 		g_free (gdaui_entry_rt->priv);
153 		gdaui_entry_rt->priv = NULL;
154 	}
155 
156 	/* parent class */
157 	parent_class->finalize (object);
158 }
159 
160 static GtkWidget *
161 create_entry (GdauiEntryWrapper *mgwrap)
162 {
163 	GdauiEntryRt *mgtxt;
164 
165 	g_return_val_if_fail (mgwrap && GDAUI_IS_ENTRY_RT (mgwrap), NULL);
166 	mgtxt = GDAUI_ENTRY_RT (mgwrap);
167 	g_return_val_if_fail (mgtxt->priv, NULL);
168 
169 	mgtxt->priv->view = gdaui_rt_editor_new ();
170 
171 	return mgtxt->priv->view;
172 }
173 
174 static void
175 real_set_value (GdauiEntryWrapper *mgwrap, const GValue *value)
176 {
177 	GdauiEntryRt *mgtxt;
178 
common_bin_create_menu(BinMenu * binmenu,PopupContainerPositionFunc pos_func,GType entry_type,BinCallback loaded_value_cb,gpointer loaded_value_cb_data)179 	g_return_if_fail (mgwrap && GDAUI_IS_ENTRY_RT (mgwrap));
180 	mgtxt = GDAUI_ENTRY_RT (mgwrap);
181 	g_return_if_fail (mgtxt->priv);
182 
183 	gdaui_rt_editor_set_contents (GDAUI_RT_EDITOR (mgtxt->priv->view), "", -1);
184 	if (value) {
185 		if (! gda_value_is_null ((GValue *) value)) {
186 			GdaDataHandler *dh;
187 			gchar *str;
188 			gboolean done = FALSE;
189 
190 			if (G_VALUE_TYPE (value) == GDA_TYPE_BLOB) {
191 				const GdaBlob *blob;
192 				GdaBinary *bin;
193 				blob = gda_value_get_blob (value);
194 				bin = (GdaBinary *) blob;
195 				if (blob->op &&
196 				    (bin->binary_length != gda_blob_op_get_length (blob->op)))
197                                         gda_blob_op_read_all (blob->op, (GdaBlob*) blob);
198 				if (g_utf8_validate ((gchar*) bin->data, bin->binary_length, NULL)) {
199 					gdaui_rt_editor_set_contents (GDAUI_RT_EDITOR (mgtxt->priv->view),
200 								      (gchar*) bin->data,
201 								      bin->binary_length);
202 					done = TRUE;
203 				}
204 			}
205 			else  if (G_VALUE_TYPE (value) == GDA_TYPE_BINARY) {
206 				const GdaBinary *bin;
207 				bin = gda_value_get_binary (value);
208 				if (g_utf8_validate ((gchar*) bin->data, bin->binary_length, NULL)) {
209 					gdaui_rt_editor_set_contents (GDAUI_RT_EDITOR (mgtxt->priv->view),
210 								      (gchar*) bin->data,
211 								      bin->binary_length);
212 					done = TRUE;
213 				}
214 			}
215 
216 			if (!done) {
217 				dh = gdaui_data_entry_get_handler (GDAUI_DATA_ENTRY (mgwrap));
218 				str = gda_data_handler_get_str_from_value (dh, value);
219 				if (str) {
220 					gdaui_rt_editor_set_contents (GDAUI_RT_EDITOR (mgtxt->priv->view),
221 								      str, -1);
222 					g_free (str);
223 				}
224 			}
225 		}
226 	}
227 }
228 
229 static GValue *
230 real_get_value (GdauiEntryWrapper *mgwrap)
231 {
232 	GValue *value;
format_size(gulong size)233 	GdauiEntryRt *mgtxt;
234 	GdaDataHandler *dh;
235 	gchar *str;
236 
237 	g_return_val_if_fail (mgwrap && GDAUI_IS_ENTRY_RT (mgwrap), NULL);
238 	mgtxt = GDAUI_ENTRY_RT (mgwrap);
239 	g_return_val_if_fail (mgtxt->priv, NULL);
240 
241 	dh = gdaui_data_entry_get_handler (GDAUI_DATA_ENTRY (mgwrap));
242 	str = gdaui_rt_editor_get_contents (GDAUI_RT_EDITOR (mgtxt->priv->view));
243 	value = gda_data_handler_get_value_from_str (dh, str,
244 						     gdaui_data_entry_get_value_type (GDAUI_DATA_ENTRY (mgwrap)));
245 	g_free (str);
246 	if (!value) {
247 		/* in case the gda_data_handler_get_value_from_sql() returned an error because
248 		   the contents of the GtkEntry cannot be interpreted as a GValue */
common_bin_adjust_menu(BinMenu * binmenu,gboolean editable,const GValue * value)249 		value = gda_value_new_null ();
250 	}
251 
252 	return value;
253 }
254 
255 typedef void (*Callback2) (gpointer, gpointer);
256 static gboolean
257 focus_out_cb (GtkWidget *widget, GdkEventFocus *event, GdauiEntryRt *mgtxt)
258 {
259 	GCallback activate_cb;
260 	activate_cb = g_object_get_data (G_OBJECT (widget), "_activate_cb");
261 	g_assert (activate_cb);
262 	((Callback2)activate_cb) (widget, mgtxt);
263 
264 	return gtk_widget_event (GTK_WIDGET (mgtxt), (GdkEvent*) event);
265 }
266 
267 static void
268 connect_signals(GdauiEntryWrapper *mgwrap, GCallback modify_cb, GCallback activate_cb)
269 {
270 	GdauiEntryRt *mgtxt;
271 
272 	g_return_if_fail (mgwrap && GDAUI_IS_ENTRY_RT (mgwrap));
273 	mgtxt = GDAUI_ENTRY_RT (mgwrap);
274 	g_return_if_fail (mgtxt->priv);
275 
276 	g_object_set_data (G_OBJECT (mgtxt->priv->view), "_activate_cb", activate_cb);
277 	g_signal_connect (G_OBJECT (GDAUI_RT_EDITOR (mgtxt->priv->view)), "changed",
278 			  modify_cb, mgwrap);
279 	g_signal_connect (G_OBJECT (mgtxt->priv->view), "focus-out-event",
280 			  G_CALLBACK (focus_out_cb), mgtxt);
281 	/* FIXME: how does the user "activates" the GtkRtView widget ? */
282 }
283 
284 static void
285 set_editable (GdauiEntryWrapper *mgwrap, gboolean editable)
286 {
287 	GdauiEntryRt *mgtxt;
288 
289 	g_return_if_fail (mgwrap && GDAUI_IS_ENTRY_RT (mgwrap));
290 	mgtxt = GDAUI_ENTRY_RT (mgwrap);
291 
292 	gdaui_rt_editor_set_editable (GDAUI_RT_EDITOR (mgtxt->priv->view), editable);
293 }
294