1 /*
2  *      classbuilder.c - this file is part of Geany, a fast and lightweight IDE
3  *
4  *      Copyright 2007 The Geany contributors
5  *
6  *      This program 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  *      This program 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 along
17  *      with this program; if not, write to the Free Software Foundation, Inc.,
18  *      51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 
21 /* Class Builder - creates source files containing a new class interface and definition. */
22 
23 #ifdef HAVE_CONFIG_H
24 #	include "config.h"
25 #endif
26 
27 #include "geanyplugin.h"
28 
29 GeanyData		*geany_data;
30 
31 
32 PLUGIN_VERSION_CHECK(GEANY_API_VERSION)
33 
34 PLUGIN_SET_INFO(_("Class Builder"), _("Creates source files for new class types."), VERSION,
35 	"Alexander Rodin, Ondrej Donek, the Geany developer team")
36 
37 
38 static GtkWidget *main_menu_item = NULL;
39 
40 
41 enum
42 {
43 	GEANY_CLASS_TYPE_CPP,
44 	GEANY_CLASS_TYPE_GTK,
45 	GEANY_CLASS_TYPE_PHP
46 };
47 
48 typedef struct _ClassInfo	ClassInfo;
49 
50 struct _ClassInfo
51 {
52 	gint type;
53 	gchar *namespace;
54 	gchar *namespace_up;
55 	gchar *namespace_low;
56 	gchar *class_name;
57 	gchar *class_name_up;
58 	gchar *class_name_low;
59 	gchar *base_name;
60 	gchar *base_gtype;
61 	gchar *header;
62 	gchar *header_guard;
63 	gchar *base_include;
64 	gchar *base_decl;
65 	gchar *constructor_decl;
66 	gchar *destructor_decl;
67 	gchar *source;
68 	gchar *constructor_impl;
69 	gchar *destructor_impl;
70 	gchar *gtk_destructor_registration;
71 	/* These are needed only for PHP classes */
72 	gchar *namespace_decl;
73 	gchar *implements_decl;
74 	gchar *abstract_decl;
75 	gchar *singleton_impl;
76 };
77 
78 typedef struct _CreateClassDialog
79 {
80 	gint class_type;
81 	GtkWidget *dialog;
82 	GtkWidget *class_name_entry;
83 	GtkWidget *header_entry;
84 	GtkWidget *source_entry;
85 	GtkWidget *base_name_entry;
86 	GtkWidget *base_header_entry;
87 	GtkWidget *base_header_global_box;
88 	GtkWidget *base_gtype_entry;
89 	GtkWidget *create_constructor_box;
90 	GtkWidget *create_destructor_box;
91 	GtkWidget *gtk_constructor_type_entry;
92 	/* These are needed only for PHP classes */
93 	GtkWidget *class_namespace_entry;
94 	GtkWidget *class_implements_entry;
95 	GtkWidget *create_isabstract_box;
96 	GtkWidget *create_issingleton_box;
97 } CreateClassDialog;
98 
99 
100 /* TODO make these templates configurable */
101 static const gchar templates_cpp_class_header[] = "{fileheader}\n\n\
102 #ifndef {header_guard}\n\
103 #define {header_guard}\n\
104 {base_include}\n\
105 class {class_name}{base_decl}\n\
106 {\n\
107 	public:\n\
108 		{constructor_decl}\
109 		{destructor_decl}\
110 	\n\
111 	private:\n\
112 		/* add your private declarations */\n\
113 };\n\
114 \n\
115 #endif /* {header_guard} */ \n\
116 ";
117 
118 static const gchar templates_cpp_class_source[] = "{fileheader}\n\n\
119 #include \"{header}\"\n\
120 \n\
121 {constructor_impl}\n\
122 {destructor_impl}\n\
123 ";
124 
125 static const gchar templates_gtk_class_header[] = "{fileheader}\n\n\
126 #ifndef {header_guard}_\n\
127 #define {header_guard}_ 1\n\
128 {base_include}\n\
129 G_BEGIN_DECLS\n\
130 \n\n\
131 #define {namespace_up}TYPE_{class_name_up}             ({namespace_low}{class_name_low}_get_type ())\n\
132 #define {namespace_up}{class_name_up}(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), {namespace_up}TYPE_{class_name_up}, {namespace}{class_name}))\n\
133 #define {namespace_up}{class_name_up}_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), {namespace_up}TYPE_{class_name_up}, {namespace}{class_name}Class))\n\
134 #define {namespace_up}IS_{class_name_up}(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), {namespace_up}TYPE_{class_name_up}))\n\
135 #define {namespace_up}IS_{class_name_up}_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), {namespace_up}TYPE_{class_name_up}))\n\
136 #define {namespace_up}{class_name_up}_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), {namespace_up}TYPE_{class_name_up}, {namespace}{class_name}Class))\n\
137 \n\
138 typedef struct {namespace}{class_name}_         {namespace}{class_name};\n\
139 typedef struct {namespace}{class_name}Class_    {namespace}{class_name}Class;\n\
140 typedef struct {namespace}{class_name}Private_  {namespace}{class_name}Private;\n\
141 \n\
142 struct {namespace}{class_name}_\n\
143 {\n\
144   {base_name} parent;\n\
145   /* add your public declarations here */\n\
146   {namespace}{class_name}Private *priv;\n\
147 };\n\
148 \n\
149 struct {namespace}{class_name}Class_\n\
150 {\n\
151   {base_name}Class parent_class;\n\
152 };\n\
153 \n\n\
154 GType {namespace_low}{class_name_low}_get_type (void);\n\n\
155 {constructor_decl}\
156 \n\n\
157 G_END_DECLS\n\
158 \n\
159 #endif /* {header_guard}_ */\n\
160 ";
161 
162 static const gchar templates_gtk_class_source[] = "{fileheader}\n\
163 #include \"{header}\"\n\
164 \n\
165 struct {namespace}{class_name}Private_\n\
166 {\n\
167   /* add your private declarations here */\n\
168   gpointer delete_me;\n\
169 };\n\
170 \n\
171 {destructor_decl}\
172 \n\
173 G_DEFINE_TYPE ({namespace}{class_name}, {namespace_low}{class_name_low}, {base_gtype})\n\
174 \n\n\
175 static void\n\
176 {namespace_low}{class_name_low}_class_init ({namespace}{class_name}Class *klass)\n\
177 {\n\
178   {gtk_destructor_registration}\n\
179   g_type_class_add_private ((gpointer)klass, sizeof ({namespace}{class_name}Private));\n\
180 }\n\
181 \n\
182 {destructor_impl}\n\
183 \n\
184 static void\n\
185 {namespace_low}{class_name_low}_init ({namespace}{class_name} *self)\n\
186 {\n\
187   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, {namespace_up}TYPE_{class_name_up}, {namespace}{class_name}Private);\n\
188 }\n\
189 \n\
190 {constructor_impl}\n\
191 ";
192 
193 static const gchar templates_php_class_source[] = "<?php\n\
194 {fileheader}\n\
195 {namespace_decl}\n\
196 {base_include}\n\
197 {abstract_decl}class {class_name}{base_decl}{implements_decl}\n{\n\
198 {singleton_impl}\
199 {constructor_impl}\
200 {destructor_impl}\n\
201 	// ...\n\n\
202 }\n\
203 ";
204 
205 
206 static void cc_dlg_on_set_sensitive_toggled(GtkWidget *toggle_button, GtkWidget *target_widget);
207 static void cc_dlg_on_class_name_entry_changed(GtkWidget *entry, CreateClassDialog *cc_dlg);
208 static void cc_dlg_on_class_namespace_entry_changed(GtkWidget *entry, CreateClassDialog *cc_dlg);
209 static void cc_dlg_on_base_name_entry_changed(GtkWidget *entry, CreateClassDialog *cc_dlg);
210 static gboolean create_class(CreateClassDialog *cc_dlg);
211 
212 
213 /* The list must be ended with NULL as an extra check that arg_count is correct. */
214 static void
free_pointers(gsize arg_count,...)215 free_pointers(gsize arg_count, ...)
216 {
217 	va_list a;
218 	gsize i;
219 	gpointer ptr;
220 
221 	va_start(a, arg_count);
222 	for (i = 0; i < arg_count; i++)
223 	{
224 		ptr = va_arg(a, gpointer);
225 		g_free(ptr);
226 	}
227 	ptr = va_arg(a, gpointer);
228 	if (ptr)
229 		g_warning("Wrong arg_count!");
230 	va_end(a);
231 }
232 
233 
234 static gchar*
get_template_class_header(ClassInfo * class_info)235 get_template_class_header(ClassInfo *class_info)
236 {
237 	gchar *fileheader = NULL;
238 	GString *template = NULL;
239 
240 	switch (class_info->type)
241 	{
242 		case GEANY_CLASS_TYPE_CPP:
243 			fileheader = templates_get_template_fileheader(GEANY_FILETYPES_CPP, class_info->header);
244 			template = g_string_new(templates_cpp_class_header);
245 			utils_string_replace_all(template, "{fileheader}", fileheader);
246 			utils_string_replace_all(template, "{header_guard}", class_info->header_guard);
247 			utils_string_replace_all(template, "{base_include}", class_info->base_include);
248 			utils_string_replace_all(template, "{class_name}", class_info->class_name);
249 			utils_string_replace_all(template, "{base_decl}", class_info->base_decl);
250 			utils_string_replace_all(template, "{constructor_decl}",
251 					class_info->constructor_decl);
252 			utils_string_replace_all(template, "{destructor_decl}",
253 					class_info->destructor_decl);
254 			break;
255 
256 		case GEANY_CLASS_TYPE_GTK:
257 			fileheader = templates_get_template_fileheader(GEANY_FILETYPES_C, class_info->header);
258 			template = g_string_new(templates_gtk_class_header);
259 			utils_string_replace_all(template, "{fileheader}", fileheader);
260 			utils_string_replace_all(template, "{header_guard}", class_info->header_guard);
261 			utils_string_replace_all(template, "{base_include}", class_info->base_include);
262 			utils_string_replace_all(template, "{namespace}", class_info->namespace);
263 			utils_string_replace_all(template, "{namespace_up}", class_info->namespace_up);
264 			utils_string_replace_all(template, "{namespace_low}", class_info->namespace_low);
265 			utils_string_replace_all(template, "{class_name}", class_info->class_name);
266 			utils_string_replace_all(template, "{class_name_up}", class_info->class_name_up);
267 			utils_string_replace_all(template, "{class_name_low}", class_info->class_name_low);
268 			utils_string_replace_all(template, "{base_name}", class_info->base_name);
269 			utils_string_replace_all(template, "{constructor_decl}",
270 					class_info->constructor_decl);
271 			break;
272 	}
273 
274 	g_free(fileheader);
275 
276 	if (template)
277 		return g_string_free(template, FALSE);
278 	else
279 		return NULL;
280 }
281 
282 
283 static gchar*
get_template_class_source(ClassInfo * class_info)284 get_template_class_source(ClassInfo *class_info)
285 {
286 	gchar *fileheader = NULL;
287 	GString *template = NULL;
288 
289 	switch (class_info->type)
290 	{
291 		case GEANY_CLASS_TYPE_CPP:
292 			fileheader = templates_get_template_fileheader(GEANY_FILETYPES_CPP, class_info->source);
293 			template = g_string_new(templates_cpp_class_source);
294 			utils_string_replace_all(template, "{fileheader}", fileheader);
295 			utils_string_replace_all(template, "{header}", class_info->header);
296 			utils_string_replace_all(template, "{class_name}", class_info->class_name);
297 			utils_string_replace_all(template, "{base_include}", class_info->base_include);
298 			utils_string_replace_all(template, "{base_name}", class_info->base_name);
299 			utils_string_replace_all(template, "{constructor_impl}",
300 					class_info->constructor_impl);
301 			utils_string_replace_all(template, "{destructor_impl}",
302 					class_info->destructor_impl);
303 			break;
304 
305 		case GEANY_CLASS_TYPE_GTK:
306 			fileheader = templates_get_template_fileheader(GEANY_FILETYPES_C, class_info->source);
307 			template = g_string_new(templates_gtk_class_source);
308 			utils_string_replace_all(template, "{fileheader}", fileheader);
309 			utils_string_replace_all(template, "{header}", class_info->header);
310 			utils_string_replace_all(template, "{namespace}", class_info->namespace);
311 			utils_string_replace_all(template, "{namespace_up}", class_info->namespace_up);
312 			utils_string_replace_all(template, "{namespace_low}", class_info->namespace_low);
313 			utils_string_replace_all(template, "{class_name}", class_info->class_name);
314 			utils_string_replace_all(template, "{class_name_up}", class_info->class_name_up);
315 			utils_string_replace_all(template, "{class_name_low}", class_info->class_name_low);
316 			utils_string_replace_all(template, "{base_name}", class_info->base_name);
317 			utils_string_replace_all(template, "{base_gtype}", class_info->base_gtype);
318 			utils_string_replace_all(template, "{destructor_decl}", class_info->destructor_decl);
319 			utils_string_replace_all(template, "{constructor_impl}",
320 					class_info->constructor_impl);
321 			utils_string_replace_all(template, "{destructor_impl}",
322 					class_info->destructor_impl);
323 			utils_string_replace_all(template, "{gtk_destructor_registration}",
324 					class_info->gtk_destructor_registration);
325 			break;
326 
327 		case GEANY_CLASS_TYPE_PHP:
328 			fileheader = templates_get_template_fileheader(GEANY_FILETYPES_PHP, class_info->source);
329 			template = g_string_new(templates_php_class_source);
330 			utils_string_replace_all(template, "{fileheader}", fileheader);
331 			utils_string_replace_all(template, "{namespace_decl}", class_info->namespace_decl);
332 			utils_string_replace_all(template, "{base_include}", class_info->base_include);
333 			utils_string_replace_all(template, "{abstract_decl}", class_info->abstract_decl);
334 			utils_string_replace_all(template, "{class_name}", class_info->class_name);
335 			utils_string_replace_all(template, "{base_decl}", class_info->base_decl);
336 			utils_string_replace_all(template, "{implements_decl}", class_info->implements_decl);
337 			utils_string_replace_all(template, "{constructor_impl}", class_info->constructor_impl);
338 			utils_string_replace_all(template, "{destructor_impl}", class_info->destructor_impl);
339 			utils_string_replace_all(template, "{singleton_impl}", class_info->singleton_impl);
340 			break;
341 	}
342 
343 	g_free(fileheader);
344 
345 	if (template)
346 		return g_string_free(template, FALSE);
347 	else
348 		return NULL;
349 }
350 
351 /* Creates a new option label, indented on the left */
cc_option_label_new(const gchar * text)352 static GtkWidget *cc_option_label_new(const gchar *text)
353 {
354 	GtkWidget *align;
355 	GtkWidget *label;
356 
357 	align = gtk_alignment_new(0.0, 0.5, 1.0, 1.0);
358 	gtk_alignment_set_padding(GTK_ALIGNMENT(align), 0, 0, 12, 0);
359 
360 	label = gtk_label_new(text);
361 	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
362 	gtk_container_add(GTK_CONTAINER(align), label);
363 
364 	return align;
365 }
366 
367 /* Attaches a new section label at the specified table row, optionally
368  * padded at the top, and returns the new label. */
cc_table_attach_section_label(GtkWidget * table,const gchar * text,guint row,gboolean top_padding)369 static GtkWidget *cc_table_attach_section_label(GtkWidget *table, const gchar *text,
370 		guint row, gboolean top_padding)
371 {
372 	gchar *markup;
373 	GtkWidget *label, *align;
374 
375 	label = gtk_label_new(NULL);
376 	markup = g_markup_printf_escaped("<b>%s</b>", text);
377 	gtk_label_set_markup(GTK_LABEL(label), markup);
378 	g_free(markup);
379 	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
380 
381 	align = gtk_alignment_new(0.0, 0.5, 1.0, 1.0);
382 	if (top_padding)
383 		gtk_alignment_set_padding(GTK_ALIGNMENT(align), 6, 0, 0, 0);
384 	gtk_container_add(GTK_CONTAINER(align), label);
385 
386 	gtk_table_attach(GTK_TABLE(table), align,
387 					 0, 2, row, row+1,
388 					 GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
389 
390 	return label;
391 }
392 
393 /* Attach a new option label at the specified table row and returns
394  * the label */
cc_table_attach_option_label(GtkWidget * table,const gchar * text,guint row)395 static GtkWidget *cc_table_attach_option_label(GtkWidget *table, const gchar *text, guint row)
396 {
397 	GtkWidget *opt_label = cc_option_label_new(text);
398 	gtk_table_attach(GTK_TABLE(table), opt_label,
399 					 0, 1, row, row+1,
400 					 GTK_FILL|GTK_SHRINK, GTK_FILL|GTK_SHRINK, 0, 0);
401 	return opt_label;
402 }
403 
404 /* Attach an option label and entry to the table at the specified row.
405  * The label associated with the widget is set as data on the entry
406  * with the "label" key, if access to it is needed later.  The entry
407  * widget is returned. */
cc_table_attach_option_entry(GtkWidget * table,const gchar * text,guint row)408 static GtkWidget *cc_table_attach_option_entry(GtkWidget *table, const gchar *text, guint row)
409 {
410 	GtkWidget *label;
411 	GtkWidget *entry;
412 	label = cc_table_attach_option_label(table, text, row);
413 	entry = gtk_entry_new();
414 	g_object_set_data(G_OBJECT(entry), "label", label);
415 	gtk_table_attach(GTK_TABLE(table), entry,
416 					 1, 2, row, row+1,
417 					 GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0);
418 	return entry;
419 }
420 
show_dialog_create_class(gint type)421 static void show_dialog_create_class(gint type)
422 {
423 	CreateClassDialog *cc_dlg;
424 	GtkWidget *main_box, *table, *label, *hdr_hbox;
425 	GtkWidget *opt_table, *align;
426 	guint row;
427 
428 	cc_dlg = g_new0(CreateClassDialog, 1);
429 	cc_dlg->class_type = type;
430 
431 	cc_dlg->dialog = gtk_dialog_new_with_buttons(_("Create Class"),
432 			GTK_WINDOW(geany->main_widgets->window),
433 			GTK_DIALOG_MODAL,
434 			GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
435 			GTK_STOCK_OK, GTK_RESPONSE_OK,
436 			NULL);
437 
438 	switch (type)
439 	{
440 		case GEANY_CLASS_TYPE_CPP:
441 			gtk_window_set_title(GTK_WINDOW(cc_dlg->dialog), _("Create C++ Class"));
442 			break;
443 		case GEANY_CLASS_TYPE_GTK:
444 			gtk_window_set_title(GTK_WINDOW(cc_dlg->dialog), _("Create GTK+ Class"));
445 			break;
446 		case GEANY_CLASS_TYPE_PHP:
447 			gtk_window_set_title(GTK_WINDOW(cc_dlg->dialog), _("Create PHP Class"));
448 			break;
449 	}
450 
451 	g_signal_connect_swapped(cc_dlg->dialog, "destroy", G_CALLBACK(g_free), (gpointer)cc_dlg);
452 
453 	table = gtk_table_new(13, 2, FALSE);
454 	gtk_table_set_col_spacings(GTK_TABLE(table), 6);
455 	gtk_table_set_row_spacings(GTK_TABLE(table), 6);
456 
457 	main_box = ui_dialog_vbox_new(GTK_DIALOG(cc_dlg->dialog));
458 	gtk_box_pack_start(GTK_BOX(main_box), table, TRUE, TRUE, 0);
459 
460 	row = 0;
461 
462 	if (type == GEANY_CLASS_TYPE_PHP || type == GEANY_CLASS_TYPE_GTK)
463 	{
464 		cc_table_attach_section_label(table, _("Namespace"), row++, FALSE);
465 		cc_dlg->class_namespace_entry = cc_table_attach_option_entry(table, _("Name:"), row++);
466 		g_signal_connect(cc_dlg->class_namespace_entry, "changed",
467 				G_CALLBACK(cc_dlg_on_class_namespace_entry_changed), cc_dlg);
468 	}
469 
470 	if (type == GEANY_CLASS_TYPE_PHP || type == GEANY_CLASS_TYPE_GTK)
471 		cc_table_attach_section_label(table, _("Class"), row++, TRUE);
472 	else
473 		cc_table_attach_section_label(table, _("Class"), row++, FALSE);
474 
475 	cc_dlg->class_name_entry = cc_table_attach_option_entry(table, _("Name:"), row++);
476 	g_signal_connect(cc_dlg->class_name_entry, "changed",
477 			G_CALLBACK(cc_dlg_on_class_name_entry_changed), cc_dlg);
478 
479 	if (type != GEANY_CLASS_TYPE_PHP)
480 		cc_dlg->header_entry = cc_table_attach_option_entry(table, _("Header file:"), row++);
481 
482 	cc_dlg->source_entry = cc_table_attach_option_entry(table, _("Source file:"), row++);
483 
484 	cc_table_attach_section_label(table, _("Inheritance"), row++, TRUE);
485 
486 	cc_dlg->base_name_entry = cc_table_attach_option_entry(table, _("Base class:"), row++);
487 
488 	if (type == GEANY_CLASS_TYPE_GTK)
489 		gtk_entry_set_text(GTK_ENTRY(cc_dlg->base_name_entry), "GObject");
490 	g_signal_connect(cc_dlg->base_name_entry, "changed",
491 			G_CALLBACK(cc_dlg_on_base_name_entry_changed), (gpointer)cc_dlg);
492 
493 	if (type == GEANY_CLASS_TYPE_PHP)
494 		cc_dlg->base_header_entry = cc_table_attach_option_entry(table, _("Base source:"), row++);
495 	else
496 	{
497 		hdr_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
498 
499 		label = cc_table_attach_option_label(table, _("Base header:"), row);
500 
501 		cc_dlg->base_header_entry = gtk_entry_new();
502 		g_object_set_data(G_OBJECT(cc_dlg->base_header_entry), "label", label);
503 		gtk_box_pack_start(GTK_BOX(hdr_hbox),
504 						   cc_dlg->base_header_entry,
505 						   TRUE, TRUE, 0);
506 
507 		cc_dlg->base_header_global_box = gtk_check_button_new_with_label(_("Global"));
508 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cc_dlg->base_header_global_box), TRUE);
509 		gtk_box_pack_start(GTK_BOX(hdr_hbox),
510 						   cc_dlg->base_header_global_box,
511 						   FALSE, TRUE, 0);
512 
513 		gtk_table_attach(GTK_TABLE(table), hdr_hbox,
514 						 1, 2, row, row+1,
515 						 GTK_FILL | GTK_EXPAND,
516 						 GTK_FILL | GTK_EXPAND,
517 						 0, 0);
518 		row++;
519 	}
520 
521 	if (type == GEANY_CLASS_TYPE_GTK)
522 		gtk_entry_set_text(GTK_ENTRY(cc_dlg->base_header_entry), "glib-object.h");
523 
524 	if (type == GEANY_CLASS_TYPE_GTK)
525 	{
526 		cc_dlg->base_gtype_entry = cc_table_attach_option_entry(table, _("Base GType:"), row++);
527 		gtk_entry_set_text(GTK_ENTRY(cc_dlg->base_gtype_entry), "G_TYPE_OBJECT");
528 	}
529 
530 	if (type == GEANY_CLASS_TYPE_PHP)
531 		cc_dlg->class_implements_entry = cc_table_attach_option_entry(table, _("Implements:"), row++);
532 
533 	cc_table_attach_section_label(table, _("Options"), row++, TRUE);
534 
535 	align = gtk_alignment_new(0.0, 0.5, 1.0, 1.0);
536 	gtk_alignment_set_padding(GTK_ALIGNMENT(align), 0, 0, 12, 0);
537 
538 	opt_table = gtk_table_new(1, 2, FALSE);
539 	gtk_table_set_row_spacings(GTK_TABLE(opt_table), 6);
540 	gtk_table_set_col_spacings(GTK_TABLE(opt_table), 6);
541 	gtk_container_add(GTK_CONTAINER(align), opt_table);
542 
543 	gtk_table_attach(GTK_TABLE(table), align,
544 					 0, 2, row, row+1,
545 					 GTK_FILL|GTK_EXPAND,
546 					 GTK_FILL|GTK_EXPAND,
547 					 0, 0);
548 	row++;
549 
550 	cc_dlg->create_constructor_box = gtk_check_button_new_with_label(_("Create constructor"));
551 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cc_dlg->create_constructor_box), TRUE);
552 	gtk_table_attach(GTK_TABLE(opt_table), cc_dlg->create_constructor_box,
553 					 0, 1, 0, 1, GTK_FILL|GTK_SHRINK, GTK_FILL|GTK_SHRINK, 0, 0);
554 
555 	cc_dlg->create_destructor_box = gtk_check_button_new_with_label(_("Create destructor"));
556 	gtk_table_attach(GTK_TABLE(opt_table), cc_dlg->create_destructor_box,
557 					 1, 2, 0, 1, GTK_FILL|GTK_SHRINK, GTK_FILL|GTK_SHRINK, 0, 0);
558 
559 	if (type == GEANY_CLASS_TYPE_PHP)
560 	{
561 		gtk_table_resize(GTK_TABLE(opt_table), 2, 2);
562 		cc_dlg->create_isabstract_box = gtk_check_button_new_with_label(_("Is abstract"));
563 		gtk_table_attach(GTK_TABLE(opt_table), cc_dlg->create_isabstract_box,
564 						 0, 1, 1, 2, GTK_FILL|GTK_SHRINK, GTK_FILL|GTK_SHRINK, 0, 0);
565 		cc_dlg->create_issingleton_box = gtk_check_button_new_with_label(_("Is singleton"));
566 		gtk_table_attach(GTK_TABLE(opt_table), cc_dlg->create_issingleton_box,
567 						 1, 2, 1, 2, GTK_FILL|GTK_SHRINK, GTK_FILL|GTK_SHRINK, 0, 0);
568 	}
569 
570 	gtk_widget_show_all(align);
571 
572 	if (type == GEANY_CLASS_TYPE_GTK)
573 	{
574 		cc_dlg->gtk_constructor_type_entry = cc_table_attach_option_entry(table,
575 			_("Constructor type:"), row++);
576 		gtk_entry_set_text(GTK_ENTRY(cc_dlg->gtk_constructor_type_entry), "GObject");
577 		g_signal_connect(cc_dlg->create_constructor_box, "toggled",
578 						 G_CALLBACK(cc_dlg_on_set_sensitive_toggled),
579 						 cc_dlg->gtk_constructor_type_entry);
580 	}
581 	else if (type == GEANY_CLASS_TYPE_PHP)
582 		gtk_table_resize(GTK_TABLE(table), row, 2);
583 	else if (type == GEANY_CLASS_TYPE_CPP)
584 		gtk_table_resize(GTK_TABLE(table), row, 2);
585 
586 	gtk_widget_show_all(cc_dlg->dialog);
587 	while (gtk_dialog_run(GTK_DIALOG(cc_dlg->dialog)) == GTK_RESPONSE_OK)
588 	{
589 		if (create_class(cc_dlg))
590 			break;
591 		else
592 			gdk_beep();
593 	}
594 	gtk_widget_destroy(cc_dlg->dialog);
595 }
596 
597 
cc_dlg_on_set_sensitive_toggled(GtkWidget * toggle_button,GtkWidget * target_widget)598 static void cc_dlg_on_set_sensitive_toggled(GtkWidget *toggle_button, GtkWidget *target_widget)
599 {
600 	GtkWidget *label;
601 
602 	g_return_if_fail(toggle_button != NULL);
603 	g_return_if_fail(GTK_IS_TOGGLE_BUTTON(toggle_button));
604 	g_return_if_fail(target_widget != NULL);
605 	g_return_if_fail(GTK_IS_WIDGET(target_widget));
606 
607 	label = g_object_get_data(G_OBJECT(target_widget), "label");
608 
609 	gtk_widget_set_sensitive(target_widget,
610 			gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle_button)));
611 	gtk_widget_set_sensitive(label,
612 			gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle_button)));
613 }
614 
615 
cc_dlg_update_file_names(CreateClassDialog * cc_dlg)616 static void cc_dlg_update_file_names(CreateClassDialog *cc_dlg)
617 {
618 	gchar *class_name;
619 	gchar *class_name_down;
620 	gchar *class_header = NULL;
621 	gchar *class_source = NULL;
622 
623 	g_return_if_fail(cc_dlg != NULL);
624 
625 	class_name = g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg->class_name_entry)));
626 	class_name_down = g_ascii_strdown(class_name, -1);
627 	switch (cc_dlg->class_type)
628 	{
629 		case GEANY_CLASS_TYPE_CPP:
630 		{
631 			class_header = g_strconcat(class_name_down, ".hpp", NULL);
632 			class_source = g_strconcat(class_name_down, ".cpp", NULL);
633 			break;
634 		}
635 		case GEANY_CLASS_TYPE_GTK:
636 		{
637 			const gchar *namespace;
638 			gchar *namespace_down;
639 
640 			namespace = gtk_entry_get_text(GTK_ENTRY(cc_dlg->class_namespace_entry));
641 			namespace_down = g_ascii_strdown(namespace, -1);
642 			class_header = g_strconcat(namespace_down, class_name_down, ".h", NULL);
643 			class_source = g_strconcat(namespace_down, class_name_down, ".c", NULL);
644 			g_free(namespace_down);
645 			break;
646 		}
647 		case GEANY_CLASS_TYPE_PHP:
648 		{
649 			class_header = NULL;
650 			class_source = g_strconcat(class_name, ".php", NULL);
651 			break;
652 		}
653 	}
654 
655 	if (cc_dlg->header_entry != NULL && class_header != NULL)
656 		gtk_entry_set_text(GTK_ENTRY(cc_dlg->header_entry), class_header);
657 	if (cc_dlg->source_entry != NULL && class_source != NULL)
658 		gtk_entry_set_text(GTK_ENTRY(cc_dlg->source_entry), class_source);
659 
660 	g_free(class_name);
661 	g_free(class_name_down);
662 	g_free(class_header);
663 	g_free(class_source);
664 }
665 
666 
cc_dlg_on_class_name_entry_changed(GtkWidget * entry,CreateClassDialog * cc_dlg)667 static void cc_dlg_on_class_name_entry_changed(GtkWidget *entry, CreateClassDialog *cc_dlg)
668 {
669 	cc_dlg_update_file_names(cc_dlg);
670 }
671 
672 
cc_dlg_on_class_namespace_entry_changed(GtkWidget * entry,CreateClassDialog * cc_dlg)673 static void cc_dlg_on_class_namespace_entry_changed(GtkWidget *entry, CreateClassDialog *cc_dlg)
674 {
675 
676 	if (cc_dlg->class_type == GEANY_CLASS_TYPE_GTK)
677 		cc_dlg_update_file_names(cc_dlg);
678 }
679 
680 
str_case_split(const gchar * str,gchar splitter)681 static gchar* str_case_split(const gchar *str, gchar splitter)
682 {
683 	GString *result;
684 
685 	g_return_val_if_fail(str != NULL, NULL);
686 	if (*str == '\0')
687 		return g_strdup("");
688 
689 	result = g_string_new(NULL);
690 	g_string_append_c(result, *str);
691 	while (*(++str) != '\0')
692 	{
693 		if (g_ascii_isupper(*str) && g_ascii_islower(result->str[result->len - 1]))
694 			g_string_append_c(result, splitter);
695 		g_string_append_c(result, *str);
696 	}
697 	return g_string_free(result, FALSE);
698 }
699 
700 
cc_dlg_on_base_name_entry_changed(GtkWidget * entry,CreateClassDialog * cc_dlg)701 static void cc_dlg_on_base_name_entry_changed(GtkWidget *entry, CreateClassDialog *cc_dlg)
702 {
703 	gchar *base_name_splitted;
704 	gchar *base_header;
705 	gchar *tmp;
706 
707 	g_return_if_fail(entry != NULL);
708 	g_return_if_fail(GTK_IS_ENTRY(entry));
709 	g_return_if_fail(cc_dlg != NULL);
710 
711 	base_name_splitted = str_case_split(gtk_entry_get_text(GTK_ENTRY(entry)), '_');
712 	if (! g_ascii_strncasecmp(gtk_entry_get_text(GTK_ENTRY(entry)), "gtk", 3))
713 		/*tmp = g_strconcat("gtk/", gtk_entry_get_text(GTK_ENTRY(entry)), ".h", NULL);*/
714 		/* With GTK 2.14 (and later GTK 3), single header includes are encouraged */
715 		tmp = g_strdup("gtk/gtk.h");
716 	else if (utils_str_equal(gtk_entry_get_text(GTK_ENTRY(entry)), "GObject"))
717 		tmp = g_strdup("glib-object.h");
718 	else if (cc_dlg->class_type == GEANY_CLASS_TYPE_PHP)
719 		tmp = g_strconcat(gtk_entry_get_text(GTK_ENTRY(entry)), ".php", NULL);
720 	else
721 		tmp = g_strconcat(gtk_entry_get_text(GTK_ENTRY(entry)), ".h", NULL);
722 
723 	if (cc_dlg->class_type == GEANY_CLASS_TYPE_PHP)
724 		base_header = g_strdup(tmp);
725 	else
726 		base_header = g_ascii_strdown(tmp, -1);
727 
728 	g_free(tmp);
729 
730 	gtk_entry_set_text(GTK_ENTRY(cc_dlg->base_header_entry), base_header);
731 
732 	if (cc_dlg->class_type == GEANY_CLASS_TYPE_GTK)
733 	{
734 		gchar *base_gtype;
735 		if (! g_ascii_strncasecmp(gtk_entry_get_text(GTK_ENTRY(entry)), "gtk", 3))
736 			tmp = g_strdup_printf("%.3s_TYPE%s",
737 					base_name_splitted,
738 					base_name_splitted + 3);
739 		else if (utils_str_equal(gtk_entry_get_text(GTK_ENTRY(entry)), "GObject"))
740 			tmp = g_strdup("G_TYPE_OBJECT");
741 		else
742 			tmp = g_strconcat(base_name_splitted, "_TYPE", NULL);
743 		base_gtype = g_ascii_strup(tmp, -1);
744 		gtk_entry_set_text(GTK_ENTRY(cc_dlg->base_gtype_entry), base_gtype);
745 
746 		g_free(base_gtype);
747 		g_free(tmp);
748 	}
749 
750 	g_free(base_name_splitted);
751 	g_free(base_header);
752 }
753 
754 
create_class(CreateClassDialog * cc_dlg)755 static gboolean create_class(CreateClassDialog *cc_dlg)
756 {
757 	ClassInfo *class_info;
758 	GeanyDocument *doc;
759 	gchar *text;
760 	gchar *tmp;
761 
762 	g_return_val_if_fail(cc_dlg != NULL, FALSE);
763 
764 	if (utils_str_equal(gtk_entry_get_text(GTK_ENTRY(cc_dlg->class_name_entry)), ""))
765 		return FALSE;
766 
767 	class_info = g_new0(ClassInfo, 1);
768 	class_info->type = cc_dlg->class_type;
769 	class_info->class_name = g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg->class_name_entry)));
770 	tmp = str_case_split(class_info->class_name, '_');
771 	class_info->class_name_up = g_ascii_strup(tmp, -1);
772 	class_info->class_name_low = g_ascii_strdown(class_info->class_name_up, -1);
773 	if (! utils_str_equal(gtk_entry_get_text(GTK_ENTRY(cc_dlg->base_name_entry)), ""))
774 	{
775 		class_info->base_name = g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg->base_name_entry)));
776 		if (class_info->type != GEANY_CLASS_TYPE_PHP)
777 		{
778 			class_info->base_include = g_strdup_printf("\n#include %c%s%c\n",
779 				gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->base_header_global_box)) ?
780 				'<' : '\"',
781 				gtk_entry_get_text(GTK_ENTRY(cc_dlg->base_header_entry)),
782 				gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->base_header_global_box)) ?
783 				'>' : '\"');
784 		}
785 		else
786 		{
787 			class_info->base_include = g_strdup_printf("\nrequire_once \"%s\";\n",
788 				gtk_entry_get_text(GTK_ENTRY(cc_dlg->base_header_entry)));
789 				class_info->base_decl = g_strdup_printf(" extends %s", class_info->base_name);
790 		}
791 	}
792 	else
793 	{
794 		class_info->base_name = g_strdup("");
795 		class_info->base_include = g_strdup("");
796 	}
797 	if (cc_dlg->header_entry != NULL)
798 	{
799 		class_info->header = g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg->header_entry)));
800 		class_info->header_guard = g_ascii_strup(class_info->header, -1);
801 		g_strdelimit(class_info->header_guard, ".-", '_');
802 	}
803 	switch (class_info->type)
804 	{
805 		case GEANY_CLASS_TYPE_CPP:
806 		{
807 			class_info->source = g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg->source_entry)));
808 			if (! utils_str_equal(class_info->base_name, ""))
809 				class_info->base_decl = g_strdup_printf(": public %s", class_info->base_name);
810 			else
811 				class_info->base_decl = g_strdup("");
812 			if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_constructor_box)))
813 			{
814 				gchar *base_constructor;
815 
816 				if (utils_str_equal(class_info->base_name, ""))
817 					base_constructor = g_strdup("");
818 				else
819 					base_constructor = g_strdup_printf("\t: %s()\n", class_info->base_name);
820 				class_info->constructor_decl = g_strdup_printf("%s();\n", class_info->class_name);
821 				class_info->constructor_impl = g_strdup_printf("\n%s::%s()\n%s{\n\t\n}\n",
822 					class_info->class_name, class_info->class_name, base_constructor);
823 				g_free(base_constructor);
824 			}
825 			else
826 			{
827 				class_info->constructor_decl = g_strdup("");
828 				class_info->constructor_impl = g_strdup("");
829 			}
830 			if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_destructor_box)))
831 			{
832 				class_info->destructor_decl =
833 						g_strdup_printf("virtual ~%s();\n", class_info->class_name);
834 				class_info->destructor_impl = g_strdup_printf("\n%s::~%s()\n{\n\t\n}\n",
835 					class_info->class_name, class_info->class_name);
836 			}
837 			else
838 			{
839 				class_info->destructor_decl = g_strdup("");
840 				class_info->destructor_impl = g_strdup("");
841 			}
842 			break;
843 		}
844 		case GEANY_CLASS_TYPE_GTK:
845 		{
846 			class_info->namespace = g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg->class_namespace_entry)));
847 			if (EMPTY(class_info->namespace))
848 			{
849 				class_info->namespace_up = g_strdup("");
850 				class_info->namespace_low = g_strdup("");
851 			}
852 			else
853 			{
854 				gchar *tmp_namespace;
855 				gchar *tmp_namespace_split;
856 
857 				tmp_namespace_split = str_case_split(class_info->namespace, '_');
858 				tmp_namespace = g_strconcat(tmp_namespace_split, "_", NULL);
859 				class_info->namespace_up = g_ascii_strup(tmp_namespace, -1);
860 				class_info->namespace_low = g_ascii_strdown(class_info->namespace_up, -1);
861 				g_free(tmp_namespace);
862 				g_free(tmp_namespace_split);
863 			}
864 			class_info->base_gtype = g_strdup(gtk_entry_get_text(
865 					GTK_ENTRY(cc_dlg->base_gtype_entry)));
866 			class_info->source = g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg->source_entry)));
867 			if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_constructor_box)))
868 			{
869 				class_info->constructor_decl = g_strdup_printf("%s *%s%s_new (void);\n",
870 						gtk_entry_get_text(GTK_ENTRY(cc_dlg->gtk_constructor_type_entry)),
871 						class_info->namespace_low, class_info->class_name_low);
872 				class_info->constructor_impl = g_strdup_printf("\n"
873 						"%s *\n"
874 						"%s%s_new (void)\n"
875 						"{\n"
876 						"  return g_object_new (%sTYPE_%s, NULL);\n"
877 						"}",
878 						gtk_entry_get_text(GTK_ENTRY(cc_dlg->gtk_constructor_type_entry)),
879 						class_info->namespace_low, class_info->class_name_low,
880 						class_info->namespace_up, class_info->class_name_up);
881 			}
882 			else
883 			{
884 				class_info->constructor_decl = g_strdup("");
885 				class_info->constructor_impl = g_strdup("");
886 			}
887 			if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_destructor_box)))
888 			{
889 				class_info->gtk_destructor_registration =
890 						g_strdup_printf("GObjectClass *g_object_class;\n\n"
891 						"  g_object_class = G_OBJECT_CLASS (klass);\n\n"
892 						"  g_object_class->finalize = %s%s_finalize;\n",
893 						class_info->namespace_low, class_info->class_name_low);
894 				class_info->destructor_decl =
895 						g_strdup_printf("static void %s%s_finalize (GObject *object);\n",
896 						class_info->namespace_low, class_info->class_name_low);
897 				class_info->destructor_impl = g_strdup_printf("\n"
898 						"static void\n"
899 						"%s%s_finalize (GObject *object)\n"
900 						"{\n"
901 						"  %s%s *self;\n\n"
902 						"  g_return_if_fail (%sIS_%s (object));\n\n"
903 						"  self = %s%s (object);\n\n"
904 						"  G_OBJECT_CLASS (%s%s_parent_class)->finalize (object);\n"
905 						"}\n",
906 						class_info->namespace_low,	class_info->class_name_low,
907 						class_info->namespace,		class_info->class_name,
908 						class_info->namespace_up,	class_info->class_name_up,
909 						class_info->namespace_up,	class_info->class_name_up,
910 						class_info->namespace_low,	class_info->class_name_low);
911 			}
912 			else
913 			{
914 				class_info->gtk_destructor_registration = g_strdup("");
915 				class_info->destructor_decl = g_strdup("");
916 				class_info->destructor_impl = g_strdup("");
917 			}
918 			break;
919 		}
920 		case GEANY_CLASS_TYPE_PHP:
921 		{
922 			const gchar *tmp_str;
923 
924 			class_info->source = g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg->source_entry)));
925 
926 			tmp_str = gtk_entry_get_text(GTK_ENTRY(cc_dlg->class_namespace_entry));
927 			if (! utils_str_equal(tmp_str, ""))
928 				class_info->namespace_decl = g_strdup_printf("namespace %s;", tmp_str);
929 			else
930 				class_info->namespace_decl = g_strdup("");
931 
932 			tmp_str = gtk_entry_get_text(GTK_ENTRY(cc_dlg->class_implements_entry));
933 			if (! utils_str_equal(tmp_str, ""))
934 				class_info->implements_decl = g_strdup_printf(" implements %s", tmp_str);
935 			else
936 				class_info->implements_decl = g_strdup("");
937 
938 			if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_constructor_box)) &&
939 			    ! gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_isabstract_box)))
940 			{
941 				class_info->constructor_impl = g_strdup_printf("\n"
942 					"\t/**\n"
943 					"\t * Constructor of class %s.\n"
944 					"\t *\n"
945 					"\t * @return void\n"
946 					"\t */\n"
947 					"\tpublic function __construct()\n"
948 					"\t{\n"
949 					"\t\t// ...\n"
950 					"\t}\n",
951 					class_info->class_name);
952 			}
953 			else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_constructor_box)) &&
954 			         gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_isabstract_box)))
955 			{
956 				class_info->constructor_impl = g_strdup_printf("\n"
957 					"\t/**\n"
958 					"\t * Constructor of class %s.\n"
959 					"\t *\n"
960 					"\t * @return void\n"
961 					"\t */\n"
962 					"\tprotected function __construct()\n"
963 					"\t{\n"
964 					"\t\t// ...\n"
965 					"\t}\n",
966 					class_info->class_name);
967 			}
968 			else
969 				class_info->constructor_impl = g_strdup("");
970 
971 			if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_destructor_box)))
972 			{
973 				class_info->destructor_impl = g_strdup_printf("\n"
974 					"\t/**\n"
975 					"\t * Destructor of class %s.\n"
976 					"\t *\n"
977 					"\t * @return void\n"
978 					"\t */\n"
979 					"\tpublic function __destruct()\n"
980 					"\t{\n"
981 					"\t\t// ...\n"
982 					"\t}\n",
983 					class_info->class_name);
984 			}
985 			else
986 				class_info->destructor_impl = g_strdup("");
987 
988 			if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_isabstract_box)))
989 				class_info->abstract_decl = g_strdup("abstract ");
990 			else
991 				class_info->abstract_decl = g_strdup("");
992 
993 			if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_issingleton_box)))
994 			{
995 				class_info->singleton_impl = g_strdup_printf("\n"
996 					"\t/**\n"
997 					"\t * Holds instance of self.\n"
998 					"\t * \n"
999 					"\t * @var %s\n"
1000 					"\t */\n"
1001 					"\tprotected static $kInstance = null;\n\n"
1002 					"\t/**\n"
1003 					"\t * Returns instance of self.\n"
1004 					"\t * \n"
1005 					"\t * @return %s\n"
1006 					"\t */\n"
1007 					"\tpublic static function getInstance() {\n"
1008 					"\t\tif(!(self::$kInstance instanceof %s)) {\n"
1009 					"\t\t\tself::$kInstance = new self();\n"
1010 					"\t\t}\n"
1011 					"\t\treturn self::$kInstance;\n"
1012 					"\t}\n",
1013 					class_info->class_name,
1014 					class_info->class_name,
1015 					class_info->class_name);
1016 			}
1017 			else
1018 				class_info->singleton_impl = g_strdup("");
1019 			break;
1020 		}
1021 	}
1022 
1023 	/* only create the files if the filename is not empty */
1024 	if (! utils_str_equal(class_info->source, ""))
1025 	{
1026 		doc = document_new_file(class_info->source, NULL, NULL);
1027 		text = get_template_class_source(class_info);
1028 		editor_insert_text_block(doc->editor, text, 0, -1, 0, TRUE);
1029 		g_free(text);
1030 		sci_set_current_position(doc->editor->sci, 0, TRUE);
1031 	}
1032 
1033 	if (! utils_str_equal(class_info->header, "") && class_info->type != GEANY_CLASS_TYPE_PHP)
1034 	{
1035 		doc = document_new_file(class_info->header, NULL, NULL);
1036 		text = get_template_class_header(class_info);
1037 		editor_insert_text_block(doc->editor, text, 0, -1, 0, TRUE);
1038 		g_free(text);
1039 		sci_set_current_position(doc->editor->sci, 0, TRUE);
1040 	}
1041 
1042 	free_pointers(24, tmp, class_info->namespace, class_info->namespace_up,
1043 		class_info->namespace_low, class_info->class_name, class_info->class_name_up,
1044 		class_info->base_name, class_info->class_name_low, class_info->base_include,
1045 		class_info->header, class_info->header_guard, class_info->source, class_info->base_decl,
1046 		class_info->constructor_decl, class_info->constructor_impl,
1047 		class_info->gtk_destructor_registration, class_info->destructor_decl,
1048 		class_info->destructor_impl, class_info->base_gtype,
1049 		class_info->namespace_decl, class_info->implements_decl,
1050 		class_info->abstract_decl, class_info->singleton_impl, class_info, NULL);
1051 	return TRUE;
1052 }
1053 
1054 
1055 static void
on_menu_create_cpp_class_activate(GtkMenuItem * menuitem,gpointer user_data)1056 on_menu_create_cpp_class_activate      (GtkMenuItem     *menuitem,
1057                                         gpointer         user_data)
1058 {
1059 	show_dialog_create_class(GEANY_CLASS_TYPE_CPP);
1060 }
1061 
1062 
1063 static void
on_menu_create_gtk_class_activate(GtkMenuItem * menuitem,gpointer user_data)1064 on_menu_create_gtk_class_activate      (GtkMenuItem     *menuitem,
1065                                         gpointer         user_data)
1066 {
1067 	show_dialog_create_class(GEANY_CLASS_TYPE_GTK);
1068 }
1069 
1070 
1071 static void
on_menu_create_php_class_activate(GtkMenuItem * menuitem,gpointer user_data)1072 on_menu_create_php_class_activate	(GtkMenuItem	*menuitem,
1073 					 gpointer	user_data)
1074 {
1075 	show_dialog_create_class(GEANY_CLASS_TYPE_PHP);
1076 }
1077 
1078 
plugin_init(GeanyData * data)1079 void plugin_init(GeanyData *data)
1080 {
1081 	GtkWidget *menu_create_class1;
1082 	GtkWidget *menu_create_class1_menu;
1083 	GtkWidget *menu_create_cpp_class;
1084 	GtkWidget *menu_create_gtk_class;
1085 	GtkWidget *menu_create_php_class;
1086 
1087 	menu_create_class1 = ui_image_menu_item_new (GTK_STOCK_ADD, _("Create Cla_ss"));
1088 	gtk_container_add (GTK_CONTAINER (geany->main_widgets->tools_menu), menu_create_class1);
1089 
1090 	menu_create_class1_menu = gtk_menu_new ();
1091 	gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_create_class1), menu_create_class1_menu);
1092 
1093 	menu_create_cpp_class = gtk_menu_item_new_with_mnemonic (_("_C++ Class..."));
1094 	gtk_container_add (GTK_CONTAINER (menu_create_class1_menu), menu_create_cpp_class);
1095 
1096 	menu_create_gtk_class = gtk_menu_item_new_with_mnemonic (_("_GTK+ Class..."));
1097 	gtk_container_add (GTK_CONTAINER (menu_create_class1_menu), menu_create_gtk_class);
1098 
1099 	menu_create_php_class = gtk_menu_item_new_with_mnemonic (_("_PHP Class..."));
1100 	gtk_container_add (GTK_CONTAINER (menu_create_class1_menu), menu_create_php_class);
1101 
1102 	g_signal_connect(menu_create_cpp_class, "activate",
1103 		G_CALLBACK (on_menu_create_cpp_class_activate),
1104 		NULL);
1105 	g_signal_connect(menu_create_gtk_class, "activate",
1106 		G_CALLBACK (on_menu_create_gtk_class_activate),
1107 		NULL);
1108 	g_signal_connect(menu_create_php_class, "activate",
1109 		G_CALLBACK (on_menu_create_php_class_activate),
1110 		NULL);
1111 
1112 	gtk_widget_show_all(menu_create_class1);
1113 
1114 	main_menu_item = menu_create_class1;
1115 }
1116 
1117 
plugin_cleanup(void)1118 void plugin_cleanup(void)
1119 {
1120 	gtk_widget_destroy(main_menu_item);
1121 }
1122