Fix Class Builder plugin to use correct indentation instead of
[geany-mirror.git] / plugins / classbuilder.c
blobf16cac06b532ae3030ec28a37eb259f29f43cdf8
1 /*
2 * classbuilder.c - this file is part of Geany, a fast and lightweight IDE
4 * Copyright 2007 Alexander Rodin <rodin(dot)alexander(at)gmail(dot)com>
5 * Copyright 2007-2010 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
6 * Copyright 2007-2010 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21 * MA 02110-1301, USA.
23 * $Id$
26 /* Class Builder - creates source files containing a new class interface and definition. */
28 #include "geanyplugin.h"
31 GeanyData *geany_data;
32 GeanyFunctions *geany_functions;
35 PLUGIN_VERSION_CHECK(GEANY_API_VERSION)
37 PLUGIN_SET_INFO(_("Class Builder"), _("Creates source files for new class types."), VERSION,
38 "Alexander Rodin")
41 static GtkWidget *main_menu_item = NULL;
44 enum
46 GEANY_CLASS_TYPE_CPP,
47 GEANY_CLASS_TYPE_GTK
50 typedef struct _ClassInfo ClassInfo;
52 struct _ClassInfo
54 gint type;
55 gchar *class_name;
56 gchar *class_name_up;
57 gchar *class_name_low;
58 gchar *base_name;
59 gchar *base_gtype;
60 gchar *header;
61 gchar *header_guard;
62 gchar *base_include;
63 gchar *base_decl;
64 gchar *constructor_decl;
65 gchar *destructor_decl;
66 gchar *source;
67 gchar *constructor_impl;
68 gchar *destructor_impl;
69 gchar *gtk_destructor_registration;
72 typedef struct _CreateClassDialog
74 gint class_type;
75 GtkWidget *dialog;
76 GtkWidget *class_name_entry;
77 GtkWidget *header_entry;
78 GtkWidget *source_entry;
79 GtkWidget *base_name_entry;
80 GtkWidget *base_header_entry;
81 GtkWidget *base_header_global_box;
82 GtkWidget *base_gtype_entry;
83 GtkWidget *create_constructor_box;
84 GtkWidget *create_destructor_box;
85 GtkWidget *gtk_constructor_type_entry;
86 } CreateClassDialog;
89 static const gchar templates_cpp_class_header[] = "{fileheader}\n\n\
90 #ifndef {header_guard}\n\
91 #define {header_guard}\n\
92 {base_include}\n\
93 class {class_name}{base_decl}\n\
94 {\n\
95 public:\n\
96 {constructor_decl}\
97 {destructor_decl}\
98 \n\
99 private:\n\
100 /* add your private declarations */\n\
101 };\n\
103 #endif /* {header_guard} */ \n\
106 static const gchar templates_cpp_class_source[] = "{fileheader}\n\n\
107 #include \"{header}\"\n\
109 {constructor_impl}\n\
110 {destructor_impl}\n\
113 static const gchar templates_gtk_class_header[] = "{fileheader}\n\n\
114 #ifndef __{header_guard}__\n\
115 #define __{header_guard}__\n\
116 {base_include}\n\
117 G_BEGIN_DECLS\n\
119 #define {class_name_up}_TYPE ({class_name_low}_get_type())\n\
120 #define {class_name_up}(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\\\n\
121 {class_name_up}_TYPE, {class_name}))\n\
122 #define {class_name_up}_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),\\\n\
123 {class_name_up}_TYPE, {class_name}Class))\n\
124 #define IS_{class_name_up}(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),\\\n\
125 {class_name_up}_TYPE))\n\
126 #define IS_{class_name_up}_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),\\\n\
127 {class_name_up}_TYPE))\n\
129 typedef struct _{class_name} {class_name};\n\
130 typedef struct _{class_name}Class {class_name}Class;\n\
132 struct _{class_name}Private;\n\
134 struct _{class_name}\n\
135 {\n\
136 {base_name} parent;\n\
137 /* add your public declarations here */\n\
139 struct _{class_name}Private *priv;\n\
140 };\n\
142 struct _{class_name}Class\n\
143 {\n\
144 {base_name}Class parent_class;\n\
145 };\n\
147 GType {class_name_low}_get_type (void);\n\
148 {constructor_decl}\
150 G_END_DECLS\n\
152 #endif /* __{header_guard}__ */\n\
155 static const gchar templates_gtk_class_source[] = "{fileheader}\n\
156 #include \"{header}\"\n\
158 typedef struct _{class_name}Private {class_name}Private;\n\
160 struct _{class_name}Private\n\
161 {\n\
162 /* add your private declarations here */\n\
163 };\n\
165 {destructor_decl}\
167 G_DEFINE_TYPE({class_name}, {class_name_low}, {base_gtype});\n\
168 \n\n\
169 static void {class_name_low}_class_init({class_name}Class *klass)\n\
170 {\n\
171 {gtk_destructor_registration}\n\
172 g_type_class_add_private((gpointer)klass, sizeof({class_name}Private));\n\
173 }\n\
175 {destructor_impl}\n\
177 static void {class_name_low}_init({class_name} *self)\n\
178 {\n\
179 self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self,\n\
180 {class_name_up}_TYPE, {class_name}Private);\n\
182 }\n\
184 {constructor_impl}\n\
188 static void cc_dlg_on_set_sensitive_toggled(GtkWidget *toggle_button, GtkWidget *target_widget);
189 static void cc_dlg_on_class_name_entry_changed(GtkWidget *entry, CreateClassDialog *cc_dlg);
190 static void cc_dlg_on_base_name_entry_changed(GtkWidget *entry, CreateClassDialog *cc_dlg);
191 static gboolean create_class(CreateClassDialog *cc_dlg);
194 /* The list must be ended with NULL as an extra check that arg_count is correct. */
195 static void
196 free_pointers(gsize arg_count, ...)
198 va_list a;
199 gsize i;
200 gpointer ptr;
202 va_start(a, arg_count);
203 for (i = 0; i < arg_count; i++)
205 ptr = va_arg(a, gpointer);
206 g_free(ptr);
208 ptr = va_arg(a, gpointer);
209 if (ptr)
210 g_warning("Wrong arg_count!");
211 va_end(a);
215 static gchar*
216 get_template_class_header(ClassInfo *class_info)
218 gchar *fileheader = NULL;
219 GString *template = NULL;
221 switch (class_info->type)
223 case GEANY_CLASS_TYPE_CPP:
224 fileheader = templates_get_template_fileheader(GEANY_FILETYPES_CPP, class_info->header);
225 template = g_string_new(templates_cpp_class_header);
226 utils_string_replace_all(template, "{fileheader}", fileheader);
227 utils_string_replace_all(template, "{header_guard}", class_info->header_guard);
228 utils_string_replace_all(template, "{base_include}", class_info->base_include);
229 utils_string_replace_all(template, "{class_name}", class_info->class_name);
230 utils_string_replace_all(template, "{base_decl}", class_info->base_decl);
231 utils_string_replace_all(template, "{constructor_decl}",
232 class_info->constructor_decl);
233 utils_string_replace_all(template, "{destructor_decl}",
234 class_info->destructor_decl);
235 break;
237 case GEANY_CLASS_TYPE_GTK:
238 fileheader = templates_get_template_fileheader(GEANY_FILETYPES_C, class_info->header);
239 template = g_string_new(templates_gtk_class_header);
240 utils_string_replace_all(template, "{fileheader}", fileheader);
241 utils_string_replace_all(template, "{header_guard}", class_info->header_guard);
242 utils_string_replace_all(template, "{base_include}", class_info->base_include);
243 utils_string_replace_all(template, "{class_name}", class_info->class_name);
244 utils_string_replace_all(template, "{class_name_up}", class_info->class_name_up);
245 utils_string_replace_all(template, "{class_name_low}", class_info->class_name_low);
246 utils_string_replace_all(template, "{base_name}", class_info->base_name);
247 utils_string_replace_all(template, "{constructor_decl}",
248 class_info->constructor_decl);
249 break;
252 g_free(fileheader);
254 if (template)
255 return g_string_free(template, FALSE);
256 else
257 return NULL;
261 static gchar*
262 get_template_class_source(ClassInfo *class_info)
264 gchar *fileheader = NULL;
265 GString *template = NULL;
267 switch (class_info->type)
269 case GEANY_CLASS_TYPE_CPP:
270 fileheader = templates_get_template_fileheader(GEANY_FILETYPES_CPP, class_info->source);
271 template = g_string_new(templates_cpp_class_source);
272 utils_string_replace_all(template, "{fileheader}", fileheader);
273 utils_string_replace_all(template, "{header}", class_info->header);
274 utils_string_replace_all(template, "{class_name}", class_info->class_name);
275 utils_string_replace_all(template, "{base_include}", class_info->base_include);
276 utils_string_replace_all(template, "{base_name}", class_info->base_name);
277 utils_string_replace_all(template, "{constructor_impl}",
278 class_info->constructor_impl);
279 utils_string_replace_all(template, "{destructor_impl}",
280 class_info->destructor_impl);
281 break;
283 case GEANY_CLASS_TYPE_GTK:
284 fileheader = templates_get_template_fileheader(GEANY_FILETYPES_C, class_info->source);
285 template = g_string_new(templates_gtk_class_source);
286 utils_string_replace_all(template, "{fileheader}", fileheader);
287 utils_string_replace_all(template, "{header}", class_info->header);
288 utils_string_replace_all(template, "{class_name}", class_info->class_name);
289 utils_string_replace_all(template, "{class_name_up}", class_info->class_name_up);
290 utils_string_replace_all(template, "{class_name_low}", class_info->class_name_low);
291 utils_string_replace_all(template, "{base_name}", class_info->base_name);
292 utils_string_replace_all(template, "{base_gtype}", class_info->base_gtype);
293 utils_string_replace_all(template, "{destructor_decl}", class_info->destructor_decl);
294 utils_string_replace_all(template, "{constructor_impl}",
295 class_info->constructor_impl);
296 utils_string_replace_all(template, "{destructor_impl}",
297 class_info->destructor_impl);
298 utils_string_replace_all(template, "{gtk_destructor_registration}",
299 class_info->gtk_destructor_registration);
300 break;
303 g_free(fileheader);
305 if (template)
306 return g_string_free(template, FALSE);
307 else
308 return NULL;
312 void show_dialog_create_class(gint type)
314 CreateClassDialog *cc_dlg;
315 GtkWidget *main_box;
316 GtkWidget *frame;
317 GtkWidget *align;
318 GtkWidget *vbox;
319 GtkWidget *hbox;
320 GtkWidget *label;
322 cc_dlg = g_new0(CreateClassDialog, 1);
323 cc_dlg->class_type = type;
325 cc_dlg->dialog = gtk_dialog_new_with_buttons(_("Create Class"),
326 GTK_WINDOW(geany->main_widgets->window),
327 GTK_DIALOG_MODAL,
328 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
329 GTK_STOCK_OK, GTK_RESPONSE_OK,
330 NULL);
331 g_signal_connect_swapped(cc_dlg->dialog, "destroy", G_CALLBACK(g_free), (gpointer)cc_dlg);
333 main_box = ui_dialog_vbox_new(GTK_DIALOG(cc_dlg->dialog));
335 frame = ui_frame_new_with_alignment(_("Class"), &align);
336 gtk_container_add(GTK_CONTAINER(main_box), frame);
338 vbox = gtk_vbox_new(FALSE, 10);
339 gtk_container_add(GTK_CONTAINER(align), vbox);
341 hbox = gtk_hbox_new(FALSE, 10);
342 gtk_container_add(GTK_CONTAINER(vbox), hbox);
344 label = gtk_label_new(_("Class name:"));
345 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
347 cc_dlg->class_name_entry = gtk_entry_new();
348 gtk_box_pack_start(GTK_BOX(hbox), cc_dlg->class_name_entry, TRUE, TRUE, 0);
349 g_signal_connect(cc_dlg->class_name_entry, "changed",
350 G_CALLBACK(cc_dlg_on_class_name_entry_changed), cc_dlg);
352 hbox = gtk_hbox_new(FALSE, 10);
353 gtk_container_add(GTK_CONTAINER(vbox), hbox);
355 label = gtk_label_new(_("Header file:"));
356 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
358 cc_dlg->header_entry = gtk_entry_new();
359 gtk_container_add(GTK_CONTAINER(hbox), cc_dlg->header_entry);
361 hbox = gtk_hbox_new(FALSE, 10);
362 gtk_container_add(GTK_CONTAINER(vbox), hbox);
364 label = gtk_label_new(_("Source file:"));
365 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
367 cc_dlg->source_entry = gtk_entry_new();
368 gtk_container_add(GTK_CONTAINER(hbox), cc_dlg->source_entry);
370 frame = ui_frame_new_with_alignment(_("Inheritance"), &align);
371 gtk_container_add(GTK_CONTAINER(main_box), frame);
373 vbox = gtk_vbox_new(FALSE, 10);
374 gtk_container_add(GTK_CONTAINER(align), vbox);
376 hbox = gtk_hbox_new(FALSE, 10);
377 gtk_container_add(GTK_CONTAINER(vbox), hbox);
379 label = gtk_label_new(_("Base class:"));
380 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
382 cc_dlg->base_name_entry = gtk_entry_new();
383 if (type == GEANY_CLASS_TYPE_GTK)
384 gtk_entry_set_text(GTK_ENTRY(cc_dlg->base_name_entry), "GObject");
385 gtk_container_add(GTK_CONTAINER(hbox), cc_dlg->base_name_entry);
386 g_signal_connect(cc_dlg->base_name_entry, "changed",
387 G_CALLBACK(cc_dlg_on_base_name_entry_changed), (gpointer)cc_dlg);
389 hbox = gtk_hbox_new(FALSE, 10);
390 gtk_container_add(GTK_CONTAINER(vbox), hbox);
392 label = gtk_label_new(_("Base header:"));
393 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
395 cc_dlg->base_header_entry = gtk_entry_new();
396 if (type == GEANY_CLASS_TYPE_GTK)
397 gtk_entry_set_text(GTK_ENTRY(cc_dlg->base_header_entry), "glib-object.h");
398 gtk_container_add(GTK_CONTAINER(hbox), cc_dlg->base_header_entry);
400 cc_dlg->base_header_global_box = gtk_check_button_new_with_label(_("Global"));
401 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cc_dlg->base_header_global_box), TRUE);
402 gtk_box_pack_end(GTK_BOX(hbox), cc_dlg->base_header_global_box, FALSE, FALSE, 0);
404 if (type == GEANY_CLASS_TYPE_GTK)
406 hbox = gtk_hbox_new(FALSE, 10);
407 gtk_container_add(GTK_CONTAINER(vbox), hbox);
409 label = gtk_label_new(_("Base GType:"));
410 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
412 cc_dlg->base_gtype_entry = gtk_entry_new();
413 gtk_entry_set_text(GTK_ENTRY(cc_dlg->base_gtype_entry), "G_TYPE_OBJECT");
414 gtk_container_add(GTK_CONTAINER(hbox), cc_dlg->base_gtype_entry);
417 frame = ui_frame_new_with_alignment(_("Options"), &align);
418 gtk_container_add(GTK_CONTAINER(main_box), frame);
420 vbox = gtk_vbox_new(FALSE, 10);
421 gtk_container_add(GTK_CONTAINER(align), vbox);
423 hbox = gtk_hbox_new(FALSE, 10);
424 gtk_container_add(GTK_CONTAINER(vbox), hbox);
426 cc_dlg->create_constructor_box = gtk_check_button_new_with_label(_("Create constructor"));
427 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cc_dlg->create_constructor_box), TRUE);
428 gtk_container_add(GTK_CONTAINER(hbox), cc_dlg->create_constructor_box);
430 cc_dlg->create_destructor_box = gtk_check_button_new_with_label(_("Create destructor"));
431 gtk_container_add(GTK_CONTAINER(hbox), cc_dlg->create_destructor_box);
433 if (type == GEANY_CLASS_TYPE_GTK)
435 hbox = gtk_hbox_new(FALSE, 10);
436 gtk_container_add(GTK_CONTAINER(vbox), hbox);
437 g_signal_connect(cc_dlg->create_constructor_box, "toggled",
438 G_CALLBACK(cc_dlg_on_set_sensitive_toggled), (gpointer)hbox);
440 label = gtk_label_new(_("GTK+ constructor type"));
441 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
443 cc_dlg->gtk_constructor_type_entry = gtk_entry_new();
444 gtk_entry_set_text(GTK_ENTRY(cc_dlg->gtk_constructor_type_entry), "GObject");
445 gtk_container_add(GTK_CONTAINER(hbox), cc_dlg->gtk_constructor_type_entry);
448 gtk_widget_show_all(cc_dlg->dialog);
449 while (gtk_dialog_run(GTK_DIALOG(cc_dlg->dialog)) == GTK_RESPONSE_OK)
451 if (create_class(cc_dlg))
452 break;
453 else
454 gdk_beep();
456 gtk_widget_destroy(cc_dlg->dialog);
457 /* g_object_unref(G_OBJECT(cc_dlg->dialog)); */
461 static void cc_dlg_on_set_sensitive_toggled(GtkWidget *toggle_button, GtkWidget *target_widget)
463 g_return_if_fail(toggle_button != NULL);
464 g_return_if_fail(GTK_IS_TOGGLE_BUTTON(toggle_button));
465 g_return_if_fail(target_widget != NULL);
466 g_return_if_fail(GTK_IS_WIDGET(target_widget));
468 gtk_widget_set_sensitive(target_widget,
469 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle_button)));
473 static void cc_dlg_on_class_name_entry_changed(GtkWidget *entry, CreateClassDialog *cc_dlg)
475 gchar *class_name_down;
476 gchar *class_header;
477 gchar *class_source;
479 g_return_if_fail(entry != NULL);
480 g_return_if_fail(GTK_IS_ENTRY(entry));
481 g_return_if_fail(cc_dlg != NULL);
483 class_name_down = g_ascii_strdown(gtk_entry_get_text(GTK_ENTRY(entry)), -1);
484 class_header = g_strconcat(class_name_down, ".h", NULL);
485 if (cc_dlg->class_type == GEANY_CLASS_TYPE_CPP)
486 class_source = g_strconcat(class_name_down, ".cpp", NULL);
487 else
488 class_source = g_strconcat(class_name_down, ".c", NULL);
490 gtk_entry_set_text(GTK_ENTRY(cc_dlg->header_entry), class_header);
491 gtk_entry_set_text(GTK_ENTRY(cc_dlg->source_entry), class_source);
493 g_free(class_name_down);
494 g_free(class_header);
495 g_free(class_source);
499 static gchar* str_case_split(const gchar *str, gchar splitter)
501 GString *result;
503 g_return_val_if_fail(str != NULL, NULL);
504 if (*str == '\0')
505 return g_strdup("");
507 result = g_string_new(NULL);
508 g_string_append_c(result, *str);
509 while (*(++str) != '\0')
511 if (g_ascii_isupper(*str) && g_ascii_islower(result->str[result->len - 1]))
512 g_string_append_c(result, splitter);
513 g_string_append_c(result, *str);
515 return g_string_free(result, FALSE);
519 static void cc_dlg_on_base_name_entry_changed(GtkWidget *entry, CreateClassDialog *cc_dlg)
521 gchar *base_name_splitted;
522 gchar *base_header;
523 gchar *tmp;
525 g_return_if_fail(entry != NULL);
526 g_return_if_fail(GTK_IS_ENTRY(entry));
527 g_return_if_fail(cc_dlg != NULL);
529 base_name_splitted = str_case_split(gtk_entry_get_text(GTK_ENTRY(entry)), '_');
530 if (! g_ascii_strncasecmp(gtk_entry_get_text(GTK_ENTRY(entry)), "gtk", 3))
531 /*tmp = g_strconcat("gtk/", gtk_entry_get_text(GTK_ENTRY(entry)), ".h", NULL);*/
532 /* With GTK 2.14 (and later GTK 3), single header includes are encouraged */
533 tmp = g_strdup("gtk/gtk.h");
534 else if (utils_str_equal(gtk_entry_get_text(GTK_ENTRY(entry)), "GObject"))
535 tmp = g_strdup("glib-object.h");
536 else
537 tmp = g_strconcat(gtk_entry_get_text(GTK_ENTRY(entry)), ".h", NULL);
538 base_header = g_ascii_strdown(tmp, -1);
539 g_free(tmp);
541 gtk_entry_set_text(GTK_ENTRY(cc_dlg->base_header_entry), base_header);
543 if (cc_dlg->class_type == GEANY_CLASS_TYPE_GTK)
545 gchar *base_gtype;
546 if (! g_ascii_strncasecmp(gtk_entry_get_text(GTK_ENTRY(entry)), "gtk", 3))
547 tmp = g_strdup_printf("%.3s_TYPE%s",
548 base_name_splitted,
549 base_name_splitted + 3);
550 else if (utils_str_equal(gtk_entry_get_text(GTK_ENTRY(entry)), "GObject"))
551 tmp = g_strdup("G_TYPE_OBJECT");
552 else
553 tmp = g_strconcat(base_name_splitted, "_TYPE", NULL);
554 base_gtype = g_ascii_strup(tmp, -1);
555 gtk_entry_set_text(GTK_ENTRY(cc_dlg->base_gtype_entry), base_gtype);
557 g_free(base_gtype);
558 g_free(tmp);
561 g_free(base_name_splitted);
562 g_free(base_header);
566 static gboolean create_class(CreateClassDialog *cc_dlg)
568 ClassInfo *class_info;
569 GeanyDocument *doc;
570 gchar *text;
571 gchar *tmp;
573 g_return_val_if_fail(cc_dlg != NULL, FALSE);
575 if (utils_str_equal(gtk_entry_get_text(GTK_ENTRY(cc_dlg->class_name_entry)), ""))
576 return FALSE;
578 class_info = g_new0(ClassInfo, 1);
579 class_info->type = cc_dlg->class_type;
580 class_info->class_name = g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg->class_name_entry)));
581 tmp = str_case_split(class_info->class_name, '_');
582 class_info->class_name_up = g_ascii_strup(tmp, -1);
583 class_info->class_name_low = g_ascii_strdown(class_info->class_name_up, -1);
584 if (! utils_str_equal(gtk_entry_get_text(GTK_ENTRY(cc_dlg->base_name_entry)), ""))
586 class_info->base_name = g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg->base_name_entry)));
587 class_info->base_include = g_strdup_printf("\n#include %c%s%c\n",
588 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->base_header_global_box)) ?
589 '<' : '\"',
590 gtk_entry_get_text(GTK_ENTRY(cc_dlg->base_header_entry)),
591 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->base_header_global_box)) ?
592 '>' : '\"');
594 else
596 class_info->base_name = g_strdup("");
597 class_info->base_include = g_strdup("");
599 class_info->header = g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg->header_entry)));
600 class_info->header_guard = g_ascii_strup(class_info->header, -1);
601 g_strdelimit(class_info->header_guard, ".-", '_');
602 switch (class_info->type)
604 case GEANY_CLASS_TYPE_CPP:
606 class_info->source = g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg->source_entry)));
607 if (! utils_str_equal(class_info->base_name, ""))
608 class_info->base_decl = g_strdup_printf(": public %s", class_info->base_name);
609 else
610 class_info->base_decl = g_strdup("");
611 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_constructor_box)))
613 gchar *base_constructor;
615 if (utils_str_equal(class_info->base_name, ""))
616 base_constructor = g_strdup("");
617 else
618 base_constructor = g_strdup_printf("\t: %s()\n", class_info->base_name);
619 class_info->constructor_decl = g_strdup_printf("%s();\n", class_info->class_name);
620 class_info->constructor_impl = g_strdup_printf("\n%s::%s()\n%s{\n\t\n}\n",
621 class_info->class_name, class_info->class_name, base_constructor);
622 g_free(base_constructor);
624 else
626 class_info->constructor_decl = g_strdup("");
627 class_info->constructor_impl = g_strdup("");
629 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_destructor_box)))
631 class_info->destructor_decl =
632 g_strdup_printf("virtual ~%s();\n", class_info->class_name);
633 class_info->destructor_impl = g_strdup_printf("\n%s::~%s()\n{\n\t\n}\n",
634 class_info->class_name, class_info->class_name);
636 else
638 class_info->destructor_decl = g_strdup("");
639 class_info->destructor_impl = g_strdup("");
641 break;
643 case GEANY_CLASS_TYPE_GTK:
645 class_info->base_gtype = g_strdup(gtk_entry_get_text(
646 GTK_ENTRY(cc_dlg->base_gtype_entry)));
647 class_info->source = g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg->source_entry)));
648 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_constructor_box)))
650 class_info->constructor_decl = g_strdup_printf("%s*\t%s_new\t\t\t(void);\n",
651 gtk_entry_get_text(GTK_ENTRY(cc_dlg->gtk_constructor_type_entry)),
652 class_info->class_name_low);
653 class_info->constructor_impl = g_strdup_printf("\n"
654 "%s *%s_new(void)\n"
655 "{\n"
656 "\treturn g_object_new(%s_TYPE, NULL);\n"
657 "}\n",
658 gtk_entry_get_text(GTK_ENTRY(cc_dlg->gtk_constructor_type_entry)),
659 class_info->class_name_low,
660 class_info->class_name_up);
662 else
664 class_info->constructor_decl = g_strdup("");
665 class_info->constructor_impl = g_strdup("");
667 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_destructor_box)))
669 class_info->gtk_destructor_registration =
670 g_strdup_printf("GObjectClass *g_object_class;\n\n"
671 "\tg_object_class = G_OBJECT_CLASS(klass);\n\n"
672 "\tg_object_class->finalize = %s_finalize;\n",
673 class_info->class_name_low);
674 class_info->destructor_decl =
675 g_strdup_printf("static void %s_finalize \t\t\t(GObject *object);\n",
676 class_info->class_name_low);
677 class_info->destructor_impl = g_strdup_printf("\n"
678 "static void %s_finalize(GObject *object)\n"
679 "{\n"
680 "\t%s *self;\n\n"
681 "\tg_return_if_fail(object != NULL);\n"
682 "\tg_return_if_fail(IS_%s(object));\n\n"
683 "\tself = %s(object);\n\n"
684 "\tG_OBJECT_CLASS(%s_parent_class)->finalize(object);\n"
685 "}\n",
686 class_info->class_name_low,
687 class_info->class_name,
688 class_info->class_name_up,
689 class_info->class_name_up,
690 class_info->class_name_low);
692 else
694 class_info->gtk_destructor_registration = g_strdup("");
695 class_info->destructor_decl = g_strdup("");
696 class_info->destructor_impl = g_strdup("");
698 break;
702 /* only create the files if the filename is not empty */
703 if (! utils_str_equal(class_info->source, ""))
705 text = get_template_class_source(class_info);
706 doc = document_new_file(class_info->source, NULL, NULL);
707 editor_insert_text_block(doc->editor, text, 0, -1, 0, TRUE);
708 g_free(text);
711 if (! utils_str_equal(class_info->header, ""))
713 text = get_template_class_header(class_info);
714 doc = document_new_file(class_info->header, NULL, NULL);
715 editor_insert_text_block(doc->editor, text, 0, -1, 0, TRUE);
716 g_free(text);
719 free_pointers(17, tmp, class_info->class_name, class_info->class_name_up,
720 class_info->base_name, class_info->class_name_low, class_info->base_include,
721 class_info->header, class_info->header_guard, class_info->source, class_info->base_decl,
722 class_info->constructor_decl, class_info->constructor_impl,
723 class_info->gtk_destructor_registration, class_info->destructor_decl,
724 class_info->destructor_impl, class_info->base_gtype, class_info, NULL);
725 return TRUE;
729 static void
730 on_menu_create_cpp_class_activate (GtkMenuItem *menuitem,
731 gpointer user_data)
733 show_dialog_create_class(GEANY_CLASS_TYPE_CPP);
737 static void
738 on_menu_create_gtk_class_activate (GtkMenuItem *menuitem,
739 gpointer user_data)
741 show_dialog_create_class(GEANY_CLASS_TYPE_GTK);
745 void plugin_init(GeanyData *data)
747 GtkWidget *menu_create_class1;
748 GtkWidget *menu_create_class1_menu;
749 GtkWidget *menu_create_cpp_class;
750 GtkWidget *menu_create_gtk_class;
752 menu_create_class1 = ui_image_menu_item_new (GTK_STOCK_ADD, _("Create Cla_ss"));
753 gtk_container_add (GTK_CONTAINER (geany->main_widgets->tools_menu), menu_create_class1);
755 menu_create_class1_menu = gtk_menu_new ();
756 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_create_class1), menu_create_class1_menu);
758 menu_create_cpp_class = gtk_menu_item_new_with_mnemonic (_("_C++ Class"));
759 gtk_container_add (GTK_CONTAINER (menu_create_class1_menu), menu_create_cpp_class);
761 menu_create_gtk_class = gtk_menu_item_new_with_mnemonic (_("_GTK+ Class"));
762 gtk_container_add (GTK_CONTAINER (menu_create_class1_menu), menu_create_gtk_class);
764 g_signal_connect(menu_create_cpp_class, "activate",
765 G_CALLBACK (on_menu_create_cpp_class_activate),
766 NULL);
767 g_signal_connect(menu_create_gtk_class, "activate",
768 G_CALLBACK (on_menu_create_gtk_class_activate),
769 NULL);
771 gtk_widget_show_all(menu_create_class1);
773 ui_add_document_sensitive(menu_create_class1);
774 main_menu_item = menu_create_class1;
778 void plugin_cleanup(void)
780 gtk_widget_destroy(main_menu_item);