1 #include <errno.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 
6 #include <gtk/gtk.h>
7 #include <glib/gstdio.h>
8 #include <glib/gi18n-lib.h>
9 
10 #include <libgda-ui/libgda-ui.h>
11 #include <libgda/binreloc/gda-binreloc.h>
12 #include <sql-parser/gda-sql-parser.h>
13 
14 #include <demos.h>
15 
16 /* to be used by example */
17 GdaConnection *demo_cnc;
18 GdaSqlParser  *demo_parser;
19 
20 
21 static GtkTextBuffer *info_buffer;
22 static GtkTextBuffer *source_buffer;
23 
24 static gchar *current_file = NULL;
25 
26 
27 enum {
28 	TITLE_COLUMN,
29 	FILENAME_COLUMN,
30 	FUNC_COLUMN,
31 	STYLE_COLUMN,
32 	NUM_COLUMNS
33 };
34 
35 typedef struct _CallbackData CallbackData;
36 struct _CallbackData
37 {
38 	GtkTreeModel *model;
39 	GtkTreePath *path;
40 };
41 
42 /**
43  * demo_find_file:
44  * @base: base filename
45  * @err:  location to store error, or %NULL.
46  *
47  * Looks for @base first in the current directory, then in the
48  * location GTK+ where it will be installed on make install,
49  * returns the first file found.
50  *
51  * Returns: the filename, if found or %NULL
52  **/
53 gchar *
demo_find_file(const char * base,GError ** err)54 demo_find_file (const char *base, GError **err)
55 {
56 	g_return_val_if_fail (err == NULL || *err == NULL, NULL);
57 
58 	if (g_file_test ("demos.h", G_FILE_TEST_EXISTS) &&
59 	    g_file_test (base, G_FILE_TEST_EXISTS))
60 		return g_strdup (base);
61 	else {
62 		gchar *filename;
63 
64 		filename = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, "demo", base, NULL);
65 		if (!g_file_test (filename, G_FILE_TEST_EXISTS)) {
66 			g_set_error (err, G_FILE_ERROR, G_FILE_ERROR_NOENT,
67 				     "Cannot find demo data file \"%s\"", base);
68 			g_free (filename);
69 			return NULL;
70 		}
71 		return filename;
72 	}
73 }
74 
75 static void
window_closed_cb(G_GNUC_UNUSED GtkWidget * window,gpointer data)76 window_closed_cb (G_GNUC_UNUSED GtkWidget *window, gpointer data)
77 {
78 	CallbackData *cbdata = data;
79 	GtkTreeIter iter;
80 	PangoStyle style;
81 
82 	gtk_tree_model_get_iter (cbdata->model, &iter, cbdata->path);
83 	gtk_tree_model_get (GTK_TREE_MODEL (cbdata->model), &iter,
84 			    STYLE_COLUMN, &style,
85 			    -1);
86 	if (style == PANGO_STYLE_ITALIC)
87 		gtk_tree_store_set (GTK_TREE_STORE (cbdata->model), &iter,
88 				    STYLE_COLUMN, PANGO_STYLE_NORMAL,
89 				    -1);
90 
91 	gtk_tree_path_free (cbdata->path);
92 	g_free (cbdata);
93 }
94 
95 gboolean
read_line(FILE * stream,GString * str)96 read_line (FILE *stream, GString *str)
97 {
98 	int n_read = 0;
99 
100 #ifdef HAVE_FLOCKFILE
101 	flockfile (stream);
102 #endif
103 
104 	g_string_truncate (str, 0);
105 
106 	while (1) {
107 		int c;
108 
109 #ifdef HAVE_FLOCKFILE
110 		c = getc_unlocked (stream);
111 #else
112 		c = getc (stream);
113 #endif
114 
115 		if (c == EOF)
116 			goto done;
117 		else
118 			n_read++;
119 
120 		switch (c) {
121 		case '\r':
122 		case '\n': {
123 #ifdef HAVE_FLOCKFILE
124 			int next_c = getc_unlocked (stream);
125 #else
126 			int next_c = getc (stream);
127 #endif
128 
129 			if (!(next_c == EOF ||
130 			      (c == '\r' && next_c == '\n') ||
131 			      (c == '\n' && next_c == '\r')))
132 				ungetc (next_c, stream);
133 
134 			goto done;
135 		}
136 		default:
137 			g_string_append_c (str, c);
138 		}
139 	}
140 
141  done:
142 
143 #ifdef HAVE_FLOCKFILE
144 	funlockfile (stream);
145 #endif
146 
147 	return n_read > 0;
148 }
149 
150 
151 /* Stupid syntax highlighting.
152  *
153  * No regex was used in the making of this highlighting.
154  * It should only work for simple cases.  This is good, as
155  * that's all we should have in the demos.
156  */
157 /* This code should not be used elsewhere, except perhaps as an example of how
158  * to iterate through a text buffer.
159  */
160 enum {
161 	STATE_NORMAL,
162 	STATE_IN_COMMENT
163 };
164 
165 static gchar *tokens[] =
166 	{
167 		"/*",
168 		"\"",
169 		NULL
170 	};
171 
172 static gchar *types[] =
173 	{
174 		"static",
175 		"const ",
176 		"void",
177 		"gint",
178 		"int ",
179 		"char ",
180 		"gchar ",
181 		"gfloat",
182 		"float",
183 		"gint8",
184 		"gint16",
185 		"gint32",
186 		"guint",
187 		"guint8",
188 		"guint16",
189 		"guint32",
190 		"guchar",
191 		"glong",
192 		"gboolean" ,
193 		"gshort",
194 		"gushort",
195 		"gulong",
196 		"gdouble",
197 		"gldouble",
198 		"gpointer",
199 		"NULL",
200 		"GList",
201 		"GSList",
202 		"FALSE",
203 		"TRUE",
204 		"FILE ",
205 		"GtkObject ",
206 		"GtkColorSelection ",
207 		"GtkWidget ",
208 		"GtkButton ",
209 		"GdkColor ",
210 		"GdkRectangle ",
211 		"GdkEventExpose ",
212 		"GdkGC ",
213 		"GdkPixbufLoader ",
214 		"GdkPixbuf ",
215 		"GError",
216 		"size_t",
217 		NULL
218 	};
219 
220 static gchar *control[] =
221 	{
222 		" if ",
223 		" while ",
224 		" else",
225 		" do ",
226 		" for ",
227 		"?",
228 		":",
229 		"return ",
230 		"goto ",
231 		NULL
232 	};
233 void
parse_chars(gchar * text,gchar ** end_ptr,gint * state,gchar ** tag,gboolean start)234 parse_chars (gchar     *text,
235 	     gchar    **end_ptr,
236 	     gint      *state,
237 	     gchar    **tag,
238 	     gboolean   start)
239 {
240 	gint i;
241 	gchar *next_token;
242 
243 	/* Handle comments first */
244 	if (*state == STATE_IN_COMMENT)	{
245 		*end_ptr = strstr (text, "*/");
246 		if (*end_ptr) {
247 			*end_ptr += 2;
248 			*state = STATE_NORMAL;
249 			*tag = "comment";
250 		}
251 		return;
252 	}
253 
254 	*tag = NULL;
255 	*end_ptr = NULL;
256 
257 	/* check for comment */
258 	if (!strncmp (text, "/*", 2)) {
259 		*end_ptr = strstr (text, "*/");
260 		if (*end_ptr)
261 			*end_ptr += 2;
262 		else
263 			*state = STATE_IN_COMMENT;
264 		*tag = "comment";
265 		return;
266 	}
267 
268 	/* check for preprocessor defines */
269 	if (*text == '#' && start) {
270 		*end_ptr = NULL;
271 		*tag = "preprocessor";
272 		return;
273 	}
274 
275 	/* functions */
276 	if (start && * text != '\t' && *text != ' ' && *text != '{' && *text != '}') {
277 		if (strstr (text, "("))	{
278 			*end_ptr = strstr (text, "(");
279 			*tag = "function";
280 			return;
281 		}
282 	}
283 	/* check for types */
284 	for (i = 0; types[i] != NULL; i++)
285 		if (!strncmp (text, types[i], strlen (types[i]))) {
286 			*end_ptr = text + strlen (types[i]);
287 			*tag = "type";
288 			return;
289 		}
290 
291 	/* check for control */
292 	for (i = 0; control[i] != NULL; i++)
293 		if (!strncmp (text, control[i], strlen (control[i]))) {
294 			*end_ptr = text + strlen (control[i]);
295 			*tag = "control";
296 			return;
297 		}
298 
299 	/* check for string */
300 	if (text[0] == '"') {
301 		gint maybe_escape = FALSE;
302 
303 		*end_ptr = text + 1;
304 		*tag = "string";
305 		while (**end_ptr != '\000') {
306 			if (**end_ptr == '\"' && !maybe_escape)	{
307 				*end_ptr += 1;
308 				return;
309 			}
310 			if (**end_ptr == '\\')
311 				maybe_escape = TRUE;
312 			else
313 				maybe_escape = FALSE;
314 			*end_ptr += 1;
315 		}
316 		return;
317 	}
318 
319 	/* not at the start of a tag.  Find the next one. */
320 	for (i = 0; tokens[i] != NULL; i++) {
321 		next_token = strstr (text, tokens[i]);
322 		if (next_token) {
323 			if (*end_ptr)
324 				*end_ptr = (*end_ptr<next_token)?*end_ptr:next_token;
325 			else
326 				*end_ptr = next_token;
327 		}
328 	}
329 
330 	for (i = 0; types[i] != NULL; i++) {
331 		next_token = strstr (text, types[i]);
332 		if (next_token)	{
333 			if (*end_ptr)
334 				*end_ptr = (*end_ptr<next_token)?*end_ptr:next_token;
335 			else
336 				*end_ptr = next_token;
337 		}
338 	}
339 
340 	for (i = 0; control[i] != NULL; i++) {
341 		next_token = strstr (text, control[i]);
342 		if (next_token)	{
343 			if (*end_ptr)
344 				*end_ptr = (*end_ptr<next_token)?*end_ptr:next_token;
345 			else
346 				*end_ptr = next_token;
347 		}
348 	}
349 }
350 
351 /* While not as cool as c-mode, this will do as a quick attempt at highlighting */
352 static void
fontify(void)353 fontify (void)
354 {
355 	GtkTextIter start_iter, next_iter, tmp_iter;
356 	gint state;
357 	gchar *text;
358 	gchar *start_ptr, *end_ptr;
359 	gchar *tag;
360 
361 	state = STATE_NORMAL;
362 
363 	gtk_text_buffer_get_iter_at_offset (source_buffer, &start_iter, 0);
364 
365 	next_iter = start_iter;
366 	while (gtk_text_iter_forward_line (&next_iter))	{
367 		gboolean start = TRUE;
368 		start_ptr = text = gtk_text_iter_get_text (&start_iter, &next_iter);
369 
370 		do {
371 			parse_chars (start_ptr, &end_ptr, &state, &tag, start);
372 
373 			start = FALSE;
374 			if (end_ptr) {
375 				tmp_iter = start_iter;
376 				gtk_text_iter_forward_chars (&tmp_iter, end_ptr - start_ptr);
377 			}
378 			else
379 				tmp_iter = next_iter;
380 			if (tag)
381 				gtk_text_buffer_apply_tag_by_name (source_buffer, tag, &start_iter, &tmp_iter);
382 
383 			start_iter = tmp_iter;
384 			start_ptr = end_ptr;
385 		}
386 		while (end_ptr);
387 
388 		g_free (text);
389 		start_iter = next_iter;
390 	}
391 }
392 
393 void
load_file(const gchar * filename)394 load_file (const gchar *filename)
395 {
396 	FILE *file;
397 	GtkTextIter start, end;
398 	char *full_filename;
399 	GError *err = NULL;
400 	GString *buffer = g_string_new (NULL);
401 	int state = 0;
402 	gboolean in_para = 0;
403 
404 	if (current_file && !strcmp (current_file, filename)) {
405 		g_string_free (buffer, TRUE);
406 		return;
407 	}
408 
409 	g_free (current_file);
410 	current_file = g_strdup (filename);
411 
412 	gtk_text_buffer_get_bounds (info_buffer, &start, &end);
413 	gtk_text_buffer_delete (info_buffer, &start, &end);
414 
415 	gtk_text_buffer_get_bounds (source_buffer, &start, &end);
416 	gtk_text_buffer_delete (source_buffer, &start, &end);
417 
418 	full_filename = demo_find_file (filename, &err);
419 	if (!full_filename) {
420 		g_warning ("%s", err->message);
421 		g_error_free (err);
422 		return;
423 	}
424 
425 	file = g_fopen (full_filename, "r");
426 
427 	if (!file)
428 		g_warning ("Cannot open %s: %s\n", full_filename, g_strerror (errno));
429 
430 	g_free (full_filename);
431 
432 	if (!file)
433 		return;
434 
435 	gtk_text_buffer_get_iter_at_offset (info_buffer, &start, 0);
436 	while (read_line (file, buffer)) {
437 		gchar *p = buffer->str;
438 		gchar *q;
439 		gchar *r;
440 
441 		switch (state) {
442 		case 0:
443 			/* Reading title */
444 			while (*p == '/' || *p == '*' || g_ascii_isspace (*p))
445 				p++;
446 			r = p;
447 			while (*r != '/' && strlen (r))
448 				r++;
449 			if (strlen (r) > 0)
450 				p = r + 1;
451 			q = p + strlen (p);
452 			while (q > p && g_ascii_isspace (*(q - 1)))
453 				q--;
454 
455 			if (q > p) {
456 				glong len_chars = g_utf8_pointer_to_offset (p, q);
457 
458 				end = start;
459 
460 				g_assert (strlen (p) >= (gsize)(q - p));
461 				gtk_text_buffer_insert (info_buffer, &end, p, q - p);
462 				start = end;
463 
464 				gtk_text_iter_backward_chars (&start, len_chars);
465 				gtk_text_buffer_apply_tag_by_name (info_buffer, "title", &start, &end);
466 
467 				start = end;
468 
469 				state++;
470 			}
471 			break;
472 
473 		case 1:
474 			/* Reading body of info section */
475 			while (g_ascii_isspace (*p))
476 				p++;
477 			if (*p == '*' && *(p + 1) == '/') {
478 				gtk_text_buffer_get_iter_at_offset (source_buffer, &start, 0);
479 				state++;
480 			}
481 			else {
482 				gsize len;
483 
484 				while (*p == '*' || g_ascii_isspace (*p))
485 					p++;
486 
487 				len = strlen (p);
488 				while ((len > 0) && g_ascii_isspace (*(p + len - 1)))
489 					len--;
490 
491 				if (len > 0) {
492 					if (in_para)
493 						gtk_text_buffer_insert (info_buffer, &start, " ", 1);
494 
495 					g_assert (strlen (p) >= len);
496 					gtk_text_buffer_insert (info_buffer, &start, p, len);
497 					in_para = 1;
498 				}
499 				else {
500 					gtk_text_buffer_insert (info_buffer, &start, "\n", 1);
501 					in_para = 0;
502 				}
503 			}
504 			break;
505 
506 		case 2:
507 			/* Skipping blank lines */
508 			while (g_ascii_isspace (*p))
509 				p++;
510 			if (*p)	{
511 				p = buffer->str;
512 				state++;
513 				/* Fall through */
514 			}
515 			else
516 				break;
517 
518 		case 3:
519 			/* Reading program body */
520 			gtk_text_buffer_insert (source_buffer, &start, p, -1);
521 			gtk_text_buffer_insert (source_buffer, &start, "\n", 1);
522 			break;
523 		}
524 	}
525 
526 	fontify ();
527 
528 	g_string_free (buffer, TRUE);
529 }
530 
531 void
row_activated_cb(GtkTreeView * tree_view,GtkTreePath * path,G_GNUC_UNUSED GtkTreeViewColumn * column)532 row_activated_cb (GtkTreeView       *tree_view,
533                   GtkTreePath       *path,
534 		  G_GNUC_UNUSED GtkTreeViewColumn *column)
535 {
536 	GtkTreeIter iter;
537 	PangoStyle style;
538 	GDoDemoFunc func;
539 	GtkWidget *window;
540 	GtkTreeModel *model;
541 
542 	model = gtk_tree_view_get_model (tree_view);
543 
544 	gtk_tree_model_get_iter (model, &iter, path);
545 	gtk_tree_model_get (GTK_TREE_MODEL (model),
546 			    &iter,
547 			    FUNC_COLUMN, &func,
548 			    STYLE_COLUMN, &style,
549 			    -1);
550 
551 	if (func) {
552 		gtk_tree_store_set (GTK_TREE_STORE (model),
553 				    &iter,
554 				    STYLE_COLUMN, (style == PANGO_STYLE_ITALIC ? PANGO_STYLE_NORMAL : PANGO_STYLE_ITALIC),
555 				    -1);
556 		window = (func) (gtk_widget_get_toplevel (GTK_WIDGET (tree_view)));
557 
558 		if (window != NULL) {
559 			CallbackData *cbdata;
560 
561 			cbdata = g_new (CallbackData, 1);
562 			cbdata->model = model;
563 			cbdata->path = gtk_tree_path_copy (path);
564 
565 			g_signal_connect (window, "destroy",
566 					  G_CALLBACK (window_closed_cb), cbdata);
567 		}
568 	}
569 }
570 
571 static void
selection_cb(GtkTreeSelection * selection,GtkTreeModel * model)572 selection_cb (GtkTreeSelection *selection,
573 	      GtkTreeModel     *model)
574 {
575 	GtkTreeIter iter;
576 	GValue *value;
577 
578 	if (! gtk_tree_selection_get_selected (selection, NULL, &iter))
579 		return;
580 
581 	value = g_slice_new0(GValue);
582 	gtk_tree_model_get_value (model, &iter,
583 				  FILENAME_COLUMN,
584 				  value);
585 	if (g_value_get_string (value))
586 		load_file (g_value_get_string (value));
587 	g_value_unset (value);
588 	g_slice_free(GValue, value);
589 }
590 
591 static GtkWidget *
create_text(GtkTextBuffer ** buffer,gboolean is_source)592 create_text (GtkTextBuffer **buffer,
593 	     gboolean        is_source)
594 {
595 	GtkWidget *scrolled_window;
596 	GtkWidget *text_view;
597 	PangoFontDescription *font_desc;
598 
599 	scrolled_window = gtk_scrolled_window_new (NULL, NULL);
600 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
601 					GTK_POLICY_AUTOMATIC,
602 					GTK_POLICY_AUTOMATIC);
603 	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
604 					     GTK_SHADOW_IN);
605 
606 	text_view = gtk_text_view_new ();
607 
608 	*buffer = gtk_text_buffer_new (NULL);
609 	gtk_text_view_set_buffer (GTK_TEXT_VIEW (text_view), *buffer);
610 	gtk_text_view_set_editable (GTK_TEXT_VIEW (text_view), FALSE);
611 	gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (text_view), FALSE);
612 
613 	gtk_container_add (GTK_CONTAINER (scrolled_window), text_view);
614 
615 	if (is_source) {
616 		font_desc = pango_font_description_from_string ("monospace");
617 		gtk_widget_override_font (text_view, font_desc);
618 		pango_font_description_free (font_desc);
619 
620 		gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view),
621 					     GTK_WRAP_NONE);
622 	}
623 	else {
624 		/* Make it a bit nicer for text. */
625 		gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view),
626 					     GTK_WRAP_WORD);
627 		gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (text_view),
628 						      2);
629 		gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (text_view),
630 						      2);
631 	}
632 
633 	return scrolled_window;
634 }
635 
636 static GtkWidget *
create_tree(void)637 create_tree (void)
638 {
639 	GtkTreeSelection *selection;
640 	GtkCellRenderer *cell;
641 	GtkWidget *tree_view;
642 	GtkTreeViewColumn *column;
643 	GtkTreeStore *model;
644 	GtkTreeIter iter;
645 	GtkWidget *box, *label, *scrolled_window;
646 
647 	Demo *d = gdaui_demos;
648 
649 	model = gtk_tree_store_new (NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_INT);
650 	tree_view = gtk_tree_view_new ();
651 	gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), GTK_TREE_MODEL (model));
652 	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
653 
654 	gtk_tree_selection_set_mode (GTK_TREE_SELECTION (selection),
655 				     GTK_SELECTION_BROWSE);
656 	gtk_widget_set_size_request (tree_view, 200, -1);
657 
658 	/* this code only supports 1 level of children. If we
659 	 * want more we probably have to use a recursing function.
660 	 */
661 	while (d->title) {
662 		Demo *children = d->children;
663 
664 		gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
665 
666 		gtk_tree_store_set (GTK_TREE_STORE (model),
667 				    &iter,
668 				    TITLE_COLUMN, d->title,
669 				    FILENAME_COLUMN, d->filename,
670 				    FUNC_COLUMN, d->func,
671 				    STYLE_COLUMN, PANGO_STYLE_NORMAL,
672 				    -1);
673 
674 		d++;
675 
676 		if (!children)
677 			continue;
678 
679 		while (children->title)	{
680 			GtkTreeIter child_iter;
681 
682 			gtk_tree_store_append (GTK_TREE_STORE (model), &child_iter, &iter);
683 
684 			gtk_tree_store_set (GTK_TREE_STORE (model),
685 							    &child_iter,
686 					    TITLE_COLUMN, children->title,
687 					    FILENAME_COLUMN, children->filename,
688 					    FUNC_COLUMN, children->func,
689 					    STYLE_COLUMN, PANGO_STYLE_NORMAL,
690 					    -1);
691 
692 			children++;
693 		}
694 	}
695 
696 	cell = gtk_cell_renderer_text_new ();
697 
698 	column = gtk_tree_view_column_new_with_attributes ("Widget (double click for demo)",
699 							   cell,
700 							   "text", TITLE_COLUMN,
701 							   "style", STYLE_COLUMN,
702 							   NULL);
703 
704 	gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
705 				     GTK_TREE_VIEW_COLUMN (column));
706 
707 	gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
708 	gtk_tree_selection_select_iter (GTK_TREE_SELECTION (selection), &iter);
709 
710 	g_signal_connect (selection, "changed", G_CALLBACK (selection_cb), model);
711 	g_signal_connect (tree_view, "row-activated", G_CALLBACK (row_activated_cb), model);
712 
713 	gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
714 	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), FALSE);
715 
716 	scrolled_window = gtk_scrolled_window_new (NULL, NULL);
717 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
718 					GTK_POLICY_NEVER,
719 					GTK_POLICY_AUTOMATIC);
720 	gtk_container_add (GTK_CONTAINER (scrolled_window), tree_view);
721 
722 	label = gtk_label_new ("Widget (double click for demo)");
723 
724 	box = gtk_notebook_new ();
725 	gtk_notebook_append_page (GTK_NOTEBOOK (box), scrolled_window, label);
726 
727 	gtk_widget_grab_focus (tree_view);
728 
729 	return box;
730 }
731 
732 int
main(int argc,char ** argv)733 main (int argc, char **argv)
734 {
735 	GtkWidget *window;
736 	GtkWidget *notebook;
737 	GtkWidget *hbox;
738 	GtkWidget *tree;
739 	GtkTextTag *tag;
740 	GError *error = NULL;
741 	gchar *full_filename, *dirname;
742 	gchar *cncstring;
743 	GtkWidget *msg;
744 	gchar *str;
745 	GdaMetaStore *mstore;
746 
747 	/* Initialize i18n support */
748 	str = gda_gbr_get_file_path (GDA_LOCALE_DIR, NULL);
749         bindtextdomain (GETTEXT_PACKAGE, str);
750 	g_free (str);
751 
752         bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
753         textdomain (GETTEXT_PACKAGE);
754 
755         /* Initialize libgda-ui & GTK+ */
756 	gtk_init (&argc, &argv);
757 	gdaui_init ();
758 
759 	/* Initialize GdaConnection object */
760 	full_filename = demo_find_file ("demo_db.db", &error);
761 	if (!full_filename) {
762 		g_warning (_("Can't find demo database file: %s"), error->message);
763 		g_error_free (error);
764 		exit (1);
765 	}
766 
767 	dirname = g_path_get_dirname (full_filename);
768 	cncstring = g_strdup_printf ("DB_DIR=%s;DB_NAME=demo_db", dirname);
769 	g_free (dirname);
770 	demo_cnc = gda_connection_open_from_string ("SQLite", cncstring, NULL, 0, &error);
771 	if (!demo_cnc) {
772 		g_warning (_("Error opening the connection for file '%s':\n%s\n"),
773 			   full_filename,
774 			   error && error->message ?  error->message : _("No detail"));
775 		g_error_free (error);
776 		exit (1);
777 	}
778 	g_free (full_filename);
779 	g_free (cncstring);
780 
781 	/* Initialize meta store */
782 	full_filename = demo_find_file ("demo_meta.db", &error);
783 	if (full_filename)
784 		mstore = gda_meta_store_new_with_file (full_filename);
785 	else
786 		mstore = gda_meta_store_new (NULL);
787 
788 	g_free (full_filename);
789 	g_object_set (G_OBJECT (demo_cnc), "meta-store", mstore, NULL);
790         g_object_unref (mstore);
791 	if (! full_filename)
792 		gda_connection_update_meta_store (demo_cnc, NULL, NULL);
793 
794 	/* Initialize parser object */
795 	demo_parser = gda_connection_create_parser (demo_cnc);
796 	if (!demo_parser)
797 		demo_parser = gda_sql_parser_new ();
798 
799 	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
800 	gtk_window_set_title (GTK_WINDOW (window), _("Libgda-ui Code Demos"));
801 	g_signal_connect (window, "destroy",
802 			  G_CALLBACK (gtk_main_quit), NULL);
803 
804 	hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
805 	gtk_container_add (GTK_CONTAINER (window), hbox);
806 
807 	tree = create_tree ();
808 	gtk_box_pack_start (GTK_BOX (hbox), tree, FALSE, FALSE, 0);
809 
810 	notebook = gtk_notebook_new ();
811 	gtk_box_pack_start (GTK_BOX (hbox), notebook, TRUE, TRUE, 0);
812 
813 	gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
814 				  create_text (&info_buffer, FALSE),
815 				  gtk_label_new_with_mnemonic ("_Info"));
816 
817 	gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
818 				  create_text (&source_buffer, TRUE),
819 				  gtk_label_new_with_mnemonic ("_Source"));
820 
821 	tag = gtk_text_buffer_create_tag (info_buffer, "title",
822 					  "font", "Sans 18",
823 					  NULL);
824 
825 	tag = gtk_text_buffer_create_tag (source_buffer, "comment",
826 					  "foreground", "DodgerBlue",
827 					  NULL);
828 	tag = gtk_text_buffer_create_tag (source_buffer, "type",
829 					  "foreground", "ForestGreen",
830 					  NULL);
831 	tag = gtk_text_buffer_create_tag (source_buffer, "string",
832 					  "foreground", "RosyBrown",
833 					  "weight", PANGO_WEIGHT_BOLD,
834 					  NULL);
835 	tag = gtk_text_buffer_create_tag (source_buffer, "control",
836 					  "foreground", "purple",
837 					  NULL);
838 	tag = gtk_text_buffer_create_tag (source_buffer, "preprocessor",
839 					  "style", PANGO_STYLE_OBLIQUE,
840 					  "foreground", "burlywood4",
841 					  NULL);
842 	tag = gtk_text_buffer_create_tag (source_buffer, "function",
843 					  "weight", PANGO_WEIGHT_BOLD,
844 					  "foreground", "DarkGoldenrod4",
845 					  NULL);
846 
847 	gtk_window_set_default_size (GTK_WINDOW (window), 600, 700);
848 	gtk_widget_show_all (window);
849 
850 	load_file (gdaui_demos[0].filename);
851 
852 	full_filename = demo_find_file ("demo_db.db", NULL);
853 	msg = gtk_message_dialog_new_with_markup (GTK_WINDOW (window), GTK_DIALOG_MODAL,
854 						  GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
855 						  _("<b><big>Note:\n</big></b>Many of the demonstrated items use an\n"
856 						    "opened connection to the SQLite using the\n"
857 						    "'%s' file.\n\n"
858 						    "In the source code shown here, the <i>demo_cnc</i> and \n"
859 						    "<i>demo_parser</i> objects are created by the framework and\n"
860 						    "made available to all the demonstrated items."), full_filename);
861 	g_free (full_filename);
862 	g_signal_connect_swapped (msg, "response",
863 				  G_CALLBACK (gtk_widget_destroy), msg);
864 	gtk_widget_show (msg);
865 
866 	gtk_main ();
867 
868 	return 0;
869 }
870