r5118 | eht16 | 2010-08-05 22:54:18 +0100 (Thu, 05 Aug 2010) | 1 line
[geany-mirror.git] / plugins / classbuilder.c
blobad345b273ba7ad5dad4808b6281920d1eeb848f7
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"
30 GeanyData *geany_data;
31 GeanyFunctions *geany_functions;
34 PLUGIN_VERSION_CHECK(GEANY_API_VERSION)
36 PLUGIN_SET_INFO(_("Class Builder"), _("Creates source files for new class types."), VERSION,
37 "Alexander Rodin, Ondrej Donek, the Geany developer team")
40 static GtkWidget *main_menu_item = NULL;
43 enum
45 GEANY_CLASS_TYPE_CPP,
46 GEANY_CLASS_TYPE_GTK,
47 GEANY_CLASS_TYPE_PHP
50 typedef struct _ClassInfo ClassInfo;
52 struct _ClassInfo
54 gint type;
55 gchar *namespace;
56 gchar *namespace_up;
57 gchar *namespace_low;
58 gchar *class_name;
59 gchar *class_name_up;
60 gchar *class_name_low;
61 gchar *base_name;
62 gchar *base_gtype;
63 gchar *header;
64 gchar *header_guard;
65 gchar *base_include;
66 gchar *base_decl;
67 gchar *constructor_decl;
68 gchar *destructor_decl;
69 gchar *source;
70 gchar *constructor_impl;
71 gchar *destructor_impl;
72 gchar *gtk_destructor_registration;
73 /* These are needed only for PHP classes */
74 gchar *namespace_decl;
75 gchar *implements_decl;
76 gchar *abstract_decl;
77 gchar *singleton_impl;
80 typedef struct _CreateClassDialog
82 gint class_type;
83 GtkWidget *dialog;
84 GtkWidget *class_name_entry;
85 GtkWidget *header_entry;
86 GtkWidget *source_entry;
87 GtkWidget *base_name_entry;
88 GtkWidget *base_header_entry;
89 GtkWidget *base_header_global_box;
90 GtkWidget *base_gtype_entry;
91 GtkWidget *create_constructor_box;
92 GtkWidget *create_destructor_box;
93 GtkWidget *gtk_constructor_type_entry;
94 /* These are needed only for PHP classes */
95 GtkWidget *class_namespace_entry;
96 GtkWidget *class_implements_entry;
97 GtkWidget *create_isabstract_box;
98 GtkWidget *create_issingleton_box;
99 } CreateClassDialog;
102 /* TODO make these templates configurable */
103 static const gchar templates_cpp_class_header[] = "{fileheader}\n\n\
104 #ifndef {header_guard}\n\
105 #define {header_guard}\n\
106 {base_include}\n\
107 class {class_name}{base_decl}\n\
108 {\n\
109 public:\n\
110 {constructor_decl}\
111 {destructor_decl}\
113 private:\n\
114 /* add your private declarations */\n\
115 };\n\
117 #endif /* {header_guard} */ \n\
120 static const gchar templates_cpp_class_source[] = "{fileheader}\n\n\
121 #include \"{header}\"\n\
123 {constructor_impl}\n\
124 {destructor_impl}\n\
127 static const gchar templates_gtk_class_header[] = "{fileheader}\n\n\
128 #ifndef __{header_guard}__\n\
129 #define __{header_guard}__\n\
130 {base_include}\n\
131 G_BEGIN_DECLS\n\
132 \n\n\
133 #define {namespace_up}TYPE_{class_name_up} ({namespace_low}{class_name_low}_get_type())\n\
134 #define {namespace_up}{class_name_up}(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\\\n\
135 {namespace_up}TYPE_{class_name_up}, {namespace}{class_name}))\n\
136 #define {namespace_up}{class_name_up}_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),\\\n\
137 {namespace_up}TYPE_{class_name_up}, {namespace}{class_name}Class))\n\
138 #define {namespace_up}IS_{class_name_up}(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),\\\n\
139 {namespace_up}TYPE_{class_name_up}))\n\
140 #define {namespace_up}IS_{class_name_up}_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),\\\n\
141 {namespace_up}TYPE_{class_name_up}))\n\
142 #define {namespace_up}{class_name_up}_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj),\\\n\
143 {namespace_up}TYPE_{class_name_up}, {namespace}{class_name}Class))\n\
145 typedef struct _{namespace}{class_name} {namespace}{class_name};\n\
146 typedef struct _{namespace}{class_name}Class {namespace}{class_name}Class;\n\
147 typedef struct _{namespace}{class_name}Private {namespace}{class_name}Private;\n\
149 struct _{namespace}{class_name}\n\
150 {\n\
151 {base_name} parent;\n\
152 /* add your public declarations here */\n\
154 {namespace}{class_name}Private *priv;\n\
155 };\n\
157 struct _{namespace}{class_name}Class\n\
158 {\n\
159 {base_name}Class parent_class;\n\
160 };\n\
161 \n\n\
162 GType {namespace_low}{class_name_low}_get_type (void);\n\
163 {constructor_decl}\
164 \n\n\
165 G_END_DECLS\n\
167 #endif /* __{header_guard}__ */\n\
170 static const gchar templates_gtk_class_source[] = "{fileheader}\n\
171 #include \"{header}\"\n\
173 struct _{namespace}{class_name}Private\n\
174 {\n\
175 /* add your private declarations here */\n\
176 };\n\
178 {destructor_decl}\
180 G_DEFINE_TYPE({namespace}{class_name}, {namespace_low}{class_name_low}, {base_gtype})\n\
181 \n\n\
182 static void {namespace_low}{class_name_low}_class_init({namespace}{class_name}Class *klass)\n\
183 {\n\
184 {gtk_destructor_registration}\n\
185 g_type_class_add_private((gpointer)klass, sizeof({namespace}{class_name}Private));\n\
186 }\n\
188 {destructor_impl}\n\
190 static void {namespace_low}{class_name_low}_init({namespace}{class_name} *self)\n\
191 {\n\
192 self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self,\n\
193 {namespace_up}TYPE_{class_name_up}, {namespace}{class_name}Private);\n\
195 }\n\
197 {constructor_impl}\n\
200 static const gchar templates_php_class_source[] = "<?php\n\
201 {fileheader}\n\
202 {namespace_decl}\n\
203 {base_include}\n\
204 {abstract_decl}class {class_name}{base_decl}{implements_decl}\n\{\n\
205 {singleton_impl}\
206 {constructor_impl}\
207 {destructor_impl}\n\
208 // ...\n\n\
209 }\n\
213 static void cc_dlg_on_set_sensitive_toggled(GtkWidget *toggle_button, GtkWidget *target_widget);
214 static void cc_dlg_on_class_name_entry_changed(GtkWidget *entry, CreateClassDialog *cc_dlg);
215 static void cc_dlg_on_class_namespace_entry_changed(GtkWidget *entry, CreateClassDialog *cc_dlg);
216 static void cc_dlg_on_base_name_entry_changed(GtkWidget *entry, CreateClassDialog *cc_dlg);
217 static gboolean create_class(CreateClassDialog *cc_dlg);
220 /* The list must be ended with NULL as an extra check that arg_count is correct. */
221 static void
222 free_pointers(gsize arg_count, ...)
224 va_list a;
225 gsize i;
226 gpointer ptr;
228 va_start(a, arg_count);
229 for (i = 0; i < arg_count; i++)
231 ptr = va_arg(a, gpointer);
232 g_free(ptr);
234 ptr = va_arg(a, gpointer);
235 if (ptr)
236 g_warning("Wrong arg_count!");
237 va_end(a);
241 static gchar*
242 get_template_class_header(ClassInfo *class_info)
244 gchar *fileheader = NULL;
245 GString *template = NULL;
247 switch (class_info->type)
249 case GEANY_CLASS_TYPE_CPP:
250 fileheader = templates_get_template_fileheader(GEANY_FILETYPES_CPP, class_info->header);
251 template = g_string_new(templates_cpp_class_header);
252 utils_string_replace_all(template, "{fileheader}", fileheader);
253 utils_string_replace_all(template, "{header_guard}", class_info->header_guard);
254 utils_string_replace_all(template, "{base_include}", class_info->base_include);
255 utils_string_replace_all(template, "{class_name}", class_info->class_name);
256 utils_string_replace_all(template, "{base_decl}", class_info->base_decl);
257 utils_string_replace_all(template, "{constructor_decl}",
258 class_info->constructor_decl);
259 utils_string_replace_all(template, "{destructor_decl}",
260 class_info->destructor_decl);
261 break;
263 case GEANY_CLASS_TYPE_GTK:
264 fileheader = templates_get_template_fileheader(GEANY_FILETYPES_C, class_info->header);
265 template = g_string_new(templates_gtk_class_header);
266 utils_string_replace_all(template, "{fileheader}", fileheader);
267 utils_string_replace_all(template, "{header_guard}", class_info->header_guard);
268 utils_string_replace_all(template, "{base_include}", class_info->base_include);
269 utils_string_replace_all(template, "{namespace}", class_info->namespace);
270 utils_string_replace_all(template, "{namespace_up}", class_info->namespace_up);
271 utils_string_replace_all(template, "{namespace_low}", class_info->namespace_low);
272 utils_string_replace_all(template, "{class_name}", class_info->class_name);
273 utils_string_replace_all(template, "{class_name_up}", class_info->class_name_up);
274 utils_string_replace_all(template, "{class_name_low}", class_info->class_name_low);
275 utils_string_replace_all(template, "{base_name}", class_info->base_name);
276 utils_string_replace_all(template, "{constructor_decl}",
277 class_info->constructor_decl);
278 break;
281 g_free(fileheader);
283 if (template)
284 return g_string_free(template, FALSE);
285 else
286 return NULL;
290 static gchar*
291 get_template_class_source(ClassInfo *class_info)
293 gchar *fileheader = NULL;
294 GString *template = NULL;
296 switch (class_info->type)
298 case GEANY_CLASS_TYPE_CPP:
299 fileheader = templates_get_template_fileheader(GEANY_FILETYPES_CPP, class_info->source);
300 template = g_string_new(templates_cpp_class_source);
301 utils_string_replace_all(template, "{fileheader}", fileheader);
302 utils_string_replace_all(template, "{header}", class_info->header);
303 utils_string_replace_all(template, "{class_name}", class_info->class_name);
304 utils_string_replace_all(template, "{base_include}", class_info->base_include);
305 utils_string_replace_all(template, "{base_name}", class_info->base_name);
306 utils_string_replace_all(template, "{constructor_impl}",
307 class_info->constructor_impl);
308 utils_string_replace_all(template, "{destructor_impl}",
309 class_info->destructor_impl);
310 break;
312 case GEANY_CLASS_TYPE_GTK:
313 fileheader = templates_get_template_fileheader(GEANY_FILETYPES_C, class_info->source);
314 template = g_string_new(templates_gtk_class_source);
315 utils_string_replace_all(template, "{fileheader}", fileheader);
316 utils_string_replace_all(template, "{header}", class_info->header);
317 utils_string_replace_all(template, "{namespace}", class_info->namespace);
318 utils_string_replace_all(template, "{namespace_up}", class_info->namespace_up);
319 utils_string_replace_all(template, "{namespace_low}", class_info->namespace_low);
320 utils_string_replace_all(template, "{class_name}", class_info->class_name);
321 utils_string_replace_all(template, "{class_name_up}", class_info->class_name_up);
322 utils_string_replace_all(template, "{class_name_low}", class_info->class_name_low);
323 utils_string_replace_all(template, "{base_name}", class_info->base_name);
324 utils_string_replace_all(template, "{base_gtype}", class_info->base_gtype);
325 utils_string_replace_all(template, "{destructor_decl}", class_info->destructor_decl);
326 utils_string_replace_all(template, "{constructor_impl}",
327 class_info->constructor_impl);
328 utils_string_replace_all(template, "{destructor_impl}",
329 class_info->destructor_impl);
330 utils_string_replace_all(template, "{gtk_destructor_registration}",
331 class_info->gtk_destructor_registration);
332 break;
334 case GEANY_CLASS_TYPE_PHP:
335 fileheader = templates_get_template_fileheader(GEANY_FILETYPES_PHP, class_info->source);
336 template = g_string_new(templates_php_class_source);
337 utils_string_replace_all(template, "{fileheader}", fileheader);
338 utils_string_replace_all(template, "{namespace_decl}", class_info->namespace_decl);
339 utils_string_replace_all(template, "{base_include}", class_info->base_include);
340 utils_string_replace_all(template, "{abstract_decl}", class_info->abstract_decl);
341 utils_string_replace_all(template, "{class_name}", class_info->class_name);
342 utils_string_replace_all(template, "{base_decl}", class_info->base_decl);
343 utils_string_replace_all(template, "{implements_decl}", class_info->implements_decl);
344 utils_string_replace_all(template, "{constructor_impl}", class_info->constructor_impl);
345 utils_string_replace_all(template, "{destructor_impl}", class_info->destructor_impl);
346 utils_string_replace_all(template, "{singleton_impl}", class_info->singleton_impl);
347 break;
350 g_free(fileheader);
352 if (template)
353 return g_string_free(template, FALSE);
354 else
355 return NULL;
359 void show_dialog_create_class(gint type)
361 CreateClassDialog *cc_dlg;
362 GtkWidget *main_box;
363 GtkWidget *frame;
364 GtkWidget *align;
365 GtkWidget *vbox;
366 GtkWidget *hbox;
367 GtkWidget *label;
369 cc_dlg = g_new0(CreateClassDialog, 1);
370 cc_dlg->class_type = type;
372 cc_dlg->dialog = gtk_dialog_new_with_buttons(_("Create Class"),
373 GTK_WINDOW(geany->main_widgets->window),
374 GTK_DIALOG_MODAL,
375 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
376 GTK_STOCK_OK, GTK_RESPONSE_OK,
377 NULL);
378 g_signal_connect_swapped(cc_dlg->dialog, "destroy", G_CALLBACK(g_free), (gpointer)cc_dlg);
380 main_box = ui_dialog_vbox_new(GTK_DIALOG(cc_dlg->dialog));
382 if (type == GEANY_CLASS_TYPE_PHP || type == GEANY_CLASS_TYPE_GTK)
384 frame = ui_frame_new_with_alignment(_("Namespace"), &align);
385 gtk_container_add(GTK_CONTAINER(main_box), frame);
387 vbox = gtk_vbox_new(FALSE, 10);
388 gtk_container_add(GTK_CONTAINER(align), vbox);
390 hbox = gtk_hbox_new(FALSE, 10);
391 gtk_container_add(GTK_CONTAINER(vbox), hbox);
393 label = gtk_label_new(_("Namespace:"));
394 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
396 cc_dlg->class_namespace_entry = gtk_entry_new();
397 gtk_box_pack_start(GTK_BOX(hbox), cc_dlg->class_namespace_entry, TRUE, TRUE, 0);
398 g_signal_connect(cc_dlg->class_namespace_entry, "changed",
399 G_CALLBACK(cc_dlg_on_class_namespace_entry_changed), cc_dlg);
402 frame = ui_frame_new_with_alignment(_("Class"), &align);
403 gtk_container_add(GTK_CONTAINER(main_box), frame);
405 vbox = gtk_vbox_new(FALSE, 10);
406 gtk_container_add(GTK_CONTAINER(align), vbox);
408 hbox = gtk_hbox_new(FALSE, 10);
409 gtk_container_add(GTK_CONTAINER(vbox), hbox);
411 label = gtk_label_new(_("Class name:"));
412 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
414 cc_dlg->class_name_entry = gtk_entry_new();
415 gtk_box_pack_start(GTK_BOX(hbox), cc_dlg->class_name_entry, TRUE, TRUE, 0);
416 g_signal_connect(cc_dlg->class_name_entry, "changed",
417 G_CALLBACK(cc_dlg_on_class_name_entry_changed), cc_dlg);
419 if (type != GEANY_CLASS_TYPE_PHP)
421 hbox = gtk_hbox_new(FALSE, 10);
422 gtk_container_add(GTK_CONTAINER(vbox), hbox);
424 label = gtk_label_new(_("Header file:"));
425 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
427 cc_dlg->header_entry = gtk_entry_new();
428 gtk_container_add(GTK_CONTAINER(hbox), cc_dlg->header_entry);
431 hbox = gtk_hbox_new(FALSE, 10);
432 gtk_container_add(GTK_CONTAINER(vbox), hbox);
434 label = gtk_label_new(_("Source file:"));
435 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
437 cc_dlg->source_entry = gtk_entry_new();
438 gtk_container_add(GTK_CONTAINER(hbox), cc_dlg->source_entry);
440 frame = ui_frame_new_with_alignment(_("Inheritance"), &align);
441 gtk_container_add(GTK_CONTAINER(main_box), frame);
443 vbox = gtk_vbox_new(FALSE, 10);
444 gtk_container_add(GTK_CONTAINER(align), vbox);
446 hbox = gtk_hbox_new(FALSE, 10);
447 gtk_container_add(GTK_CONTAINER(vbox), hbox);
449 label = gtk_label_new(_("Base class:"));
450 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
452 cc_dlg->base_name_entry = gtk_entry_new();
453 if (type == GEANY_CLASS_TYPE_GTK)
454 gtk_entry_set_text(GTK_ENTRY(cc_dlg->base_name_entry), "GObject");
455 gtk_container_add(GTK_CONTAINER(hbox), cc_dlg->base_name_entry);
456 g_signal_connect(cc_dlg->base_name_entry, "changed",
457 G_CALLBACK(cc_dlg_on_base_name_entry_changed), (gpointer)cc_dlg);
459 hbox = gtk_hbox_new(FALSE, 10);
460 gtk_container_add(GTK_CONTAINER(vbox), hbox);
462 if (type == GEANY_CLASS_TYPE_PHP)
463 label = gtk_label_new(_("Base source:"));
464 else
465 label = gtk_label_new(_("Base header:"));
466 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
468 cc_dlg->base_header_entry = gtk_entry_new();
469 if (type == GEANY_CLASS_TYPE_GTK)
470 gtk_entry_set_text(GTK_ENTRY(cc_dlg->base_header_entry), "glib-object.h");
471 gtk_container_add(GTK_CONTAINER(hbox), cc_dlg->base_header_entry);
473 if (type != GEANY_CLASS_TYPE_PHP)
475 cc_dlg->base_header_global_box = gtk_check_button_new_with_label(_("Global"));
476 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cc_dlg->base_header_global_box), TRUE);
477 gtk_box_pack_end(GTK_BOX(hbox), cc_dlg->base_header_global_box, FALSE, FALSE, 0);
480 if (type == GEANY_CLASS_TYPE_GTK)
482 hbox = gtk_hbox_new(FALSE, 10);
483 gtk_container_add(GTK_CONTAINER(vbox), hbox);
485 label = gtk_label_new(_("Base GType:"));
486 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
488 cc_dlg->base_gtype_entry = gtk_entry_new();
489 gtk_entry_set_text(GTK_ENTRY(cc_dlg->base_gtype_entry), "G_TYPE_OBJECT");
490 gtk_container_add(GTK_CONTAINER(hbox), cc_dlg->base_gtype_entry);
493 if (type == GEANY_CLASS_TYPE_PHP)
495 hbox = gtk_hbox_new(FALSE, 10);
496 gtk_container_add(GTK_CONTAINER(vbox), hbox);
498 label = gtk_label_new(_("Implements:"));
499 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
501 cc_dlg->class_implements_entry = gtk_entry_new();
502 gtk_container_add(GTK_CONTAINER(hbox), cc_dlg->class_implements_entry);
505 frame = ui_frame_new_with_alignment(_("Options"), &align);
506 gtk_container_add(GTK_CONTAINER(main_box), frame);
508 vbox = gtk_vbox_new(FALSE, 10);
509 gtk_container_add(GTK_CONTAINER(align), vbox);
511 hbox = gtk_hbox_new(FALSE, 10);
512 gtk_container_add(GTK_CONTAINER(vbox), hbox);
514 cc_dlg->create_constructor_box = gtk_check_button_new_with_label(_("Create constructor"));
515 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cc_dlg->create_constructor_box), TRUE);
516 gtk_container_add(GTK_CONTAINER(hbox), cc_dlg->create_constructor_box);
518 cc_dlg->create_destructor_box = gtk_check_button_new_with_label(_("Create destructor"));
519 gtk_container_add(GTK_CONTAINER(hbox), cc_dlg->create_destructor_box);
521 if (type == GEANY_CLASS_TYPE_PHP)
523 hbox = gtk_hbox_new(FALSE, 10);
524 gtk_container_add(GTK_CONTAINER(vbox), hbox);
526 cc_dlg->create_isabstract_box = gtk_check_button_new_with_label(_("Is abstract"));
527 gtk_container_add(GTK_CONTAINER(hbox), cc_dlg->create_isabstract_box);
529 cc_dlg->create_issingleton_box = gtk_check_button_new_with_label(_("Is singleton"));
530 gtk_container_add(GTK_CONTAINER(hbox), cc_dlg->create_issingleton_box);
533 if (type == GEANY_CLASS_TYPE_GTK)
535 hbox = gtk_hbox_new(FALSE, 10);
536 gtk_container_add(GTK_CONTAINER(vbox), hbox);
537 g_signal_connect(cc_dlg->create_constructor_box, "toggled",
538 G_CALLBACK(cc_dlg_on_set_sensitive_toggled), (gpointer)hbox);
540 label = gtk_label_new(_("GTK+ constructor type"));
541 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
543 cc_dlg->gtk_constructor_type_entry = gtk_entry_new();
544 gtk_entry_set_text(GTK_ENTRY(cc_dlg->gtk_constructor_type_entry), "GObject");
545 gtk_container_add(GTK_CONTAINER(hbox), cc_dlg->gtk_constructor_type_entry);
548 gtk_widget_show_all(cc_dlg->dialog);
549 while (gtk_dialog_run(GTK_DIALOG(cc_dlg->dialog)) == GTK_RESPONSE_OK)
551 if (create_class(cc_dlg))
552 break;
553 else
554 gdk_beep();
556 gtk_widget_destroy(cc_dlg->dialog);
560 static void cc_dlg_on_set_sensitive_toggled(GtkWidget *toggle_button, GtkWidget *target_widget)
562 g_return_if_fail(toggle_button != NULL);
563 g_return_if_fail(GTK_IS_TOGGLE_BUTTON(toggle_button));
564 g_return_if_fail(target_widget != NULL);
565 g_return_if_fail(GTK_IS_WIDGET(target_widget));
567 gtk_widget_set_sensitive(target_widget,
568 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle_button)));
572 static void cc_dlg_update_file_names(CreateClassDialog *cc_dlg)
574 gchar *class_name;
575 gchar *class_name_down;
576 gchar *class_header = NULL;
577 gchar *class_source = NULL;
579 g_return_if_fail(cc_dlg != NULL);
581 class_name = g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg->class_name_entry)));
582 class_name_down = g_ascii_strdown(class_name, -1);
583 switch (cc_dlg->class_type)
585 case GEANY_CLASS_TYPE_CPP:
587 class_header = g_strconcat(class_name_down, ".h", NULL);
588 class_source = g_strconcat(class_name_down, ".cpp", NULL);
589 break;
591 case GEANY_CLASS_TYPE_GTK:
593 const gchar *namespace;
594 gchar *namespace_down;
596 namespace = gtk_entry_get_text(GTK_ENTRY(cc_dlg->class_namespace_entry));
597 namespace_down = g_ascii_strdown(namespace, -1);
598 class_header = g_strconcat(namespace_down, class_name_down, ".h", NULL);
599 class_source = g_strconcat(namespace_down, class_name_down, ".c", NULL);
600 g_free(namespace_down);
601 break;
603 case GEANY_CLASS_TYPE_PHP:
605 class_header = NULL;
606 class_source = g_strconcat(class_name, ".php", NULL);
607 break;
611 if (cc_dlg->header_entry != NULL && class_header != NULL)
612 gtk_entry_set_text(GTK_ENTRY(cc_dlg->header_entry), class_header);
613 if (cc_dlg->source_entry != NULL && class_source != NULL)
614 gtk_entry_set_text(GTK_ENTRY(cc_dlg->source_entry), class_source);
616 g_free(class_name);
617 g_free(class_name_down);
618 g_free(class_header);
619 g_free(class_source);
623 static void cc_dlg_on_class_name_entry_changed(GtkWidget *entry, CreateClassDialog *cc_dlg)
625 cc_dlg_update_file_names(cc_dlg);
629 static void cc_dlg_on_class_namespace_entry_changed(GtkWidget *entry, CreateClassDialog *cc_dlg)
632 if (cc_dlg->class_type == GEANY_CLASS_TYPE_GTK)
633 cc_dlg_update_file_names(cc_dlg);
637 static gchar* str_case_split(const gchar *str, gchar splitter)
639 GString *result;
641 g_return_val_if_fail(str != NULL, NULL);
642 if (*str == '\0')
643 return g_strdup("");
645 result = g_string_new(NULL);
646 g_string_append_c(result, *str);
647 while (*(++str) != '\0')
649 if (g_ascii_isupper(*str) && g_ascii_islower(result->str[result->len - 1]))
650 g_string_append_c(result, splitter);
651 g_string_append_c(result, *str);
653 return g_string_free(result, FALSE);
657 static void cc_dlg_on_base_name_entry_changed(GtkWidget *entry, CreateClassDialog *cc_dlg)
659 gchar *base_name_splitted;
660 gchar *base_header;
661 gchar *tmp;
663 g_return_if_fail(entry != NULL);
664 g_return_if_fail(GTK_IS_ENTRY(entry));
665 g_return_if_fail(cc_dlg != NULL);
667 base_name_splitted = str_case_split(gtk_entry_get_text(GTK_ENTRY(entry)), '_');
668 if (! g_ascii_strncasecmp(gtk_entry_get_text(GTK_ENTRY(entry)), "gtk", 3))
669 /*tmp = g_strconcat("gtk/", gtk_entry_get_text(GTK_ENTRY(entry)), ".h", NULL);*/
670 /* With GTK 2.14 (and later GTK 3), single header includes are encouraged */
671 tmp = g_strdup("gtk/gtk.h");
672 else if (utils_str_equal(gtk_entry_get_text(GTK_ENTRY(entry)), "GObject"))
673 tmp = g_strdup("glib-object.h");
674 else if (cc_dlg->class_type == GEANY_CLASS_TYPE_PHP)
675 tmp = g_strconcat(gtk_entry_get_text(GTK_ENTRY(entry)), ".php", NULL);
676 else
677 tmp = g_strconcat(gtk_entry_get_text(GTK_ENTRY(entry)), ".h", NULL);
679 if (cc_dlg->class_type == GEANY_CLASS_TYPE_PHP)
680 base_header = g_strdup(tmp);
681 else
682 base_header = g_ascii_strdown(tmp, -1);
684 g_free(tmp);
686 gtk_entry_set_text(GTK_ENTRY(cc_dlg->base_header_entry), base_header);
688 if (cc_dlg->class_type == GEANY_CLASS_TYPE_GTK)
690 gchar *base_gtype;
691 if (! g_ascii_strncasecmp(gtk_entry_get_text(GTK_ENTRY(entry)), "gtk", 3))
692 tmp = g_strdup_printf("%.3s_TYPE%s",
693 base_name_splitted,
694 base_name_splitted + 3);
695 else if (utils_str_equal(gtk_entry_get_text(GTK_ENTRY(entry)), "GObject"))
696 tmp = g_strdup("G_TYPE_OBJECT");
697 else
698 tmp = g_strconcat(base_name_splitted, "_TYPE", NULL);
699 base_gtype = g_ascii_strup(tmp, -1);
700 gtk_entry_set_text(GTK_ENTRY(cc_dlg->base_gtype_entry), base_gtype);
702 g_free(base_gtype);
703 g_free(tmp);
706 g_free(base_name_splitted);
707 g_free(base_header);
711 static gboolean create_class(CreateClassDialog *cc_dlg)
713 ClassInfo *class_info;
714 GeanyDocument *doc;
715 gchar *text;
716 gchar *tmp;
718 g_return_val_if_fail(cc_dlg != NULL, FALSE);
720 if (utils_str_equal(gtk_entry_get_text(GTK_ENTRY(cc_dlg->class_name_entry)), ""))
721 return FALSE;
723 class_info = g_new0(ClassInfo, 1);
724 class_info->type = cc_dlg->class_type;
725 class_info->class_name = g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg->class_name_entry)));
726 tmp = str_case_split(class_info->class_name, '_');
727 class_info->class_name_up = g_ascii_strup(tmp, -1);
728 class_info->class_name_low = g_ascii_strdown(class_info->class_name_up, -1);
729 if (! utils_str_equal(gtk_entry_get_text(GTK_ENTRY(cc_dlg->base_name_entry)), ""))
731 class_info->base_name = g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg->base_name_entry)));
732 if (class_info->type != GEANY_CLASS_TYPE_PHP)
734 class_info->base_include = g_strdup_printf("\n#include %c%s%c\n",
735 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->base_header_global_box)) ?
736 '<' : '\"',
737 gtk_entry_get_text(GTK_ENTRY(cc_dlg->base_header_entry)),
738 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->base_header_global_box)) ?
739 '>' : '\"');
741 else
743 class_info->base_include = g_strdup_printf("\nrequire_once \"%s\";\n",
744 gtk_entry_get_text(GTK_ENTRY(cc_dlg->base_header_entry)));
745 class_info->base_decl = g_strdup_printf(" extends %s", class_info->base_name);
748 else
750 class_info->base_name = g_strdup("");
751 class_info->base_include = g_strdup("");
753 if (cc_dlg->header_entry != NULL)
755 class_info->header = g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg->header_entry)));
756 class_info->header_guard = g_ascii_strup(class_info->header, -1);
757 g_strdelimit(class_info->header_guard, ".-", '_');
759 switch (class_info->type)
761 case GEANY_CLASS_TYPE_CPP:
763 class_info->source = g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg->source_entry)));
764 if (! utils_str_equal(class_info->base_name, ""))
765 class_info->base_decl = g_strdup_printf(": public %s", class_info->base_name);
766 else
767 class_info->base_decl = g_strdup("");
768 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_constructor_box)))
770 gchar *base_constructor;
772 if (utils_str_equal(class_info->base_name, ""))
773 base_constructor = g_strdup("");
774 else
775 base_constructor = g_strdup_printf("\t: %s()\n", class_info->base_name);
776 class_info->constructor_decl = g_strdup_printf("%s();\n", class_info->class_name);
777 class_info->constructor_impl = g_strdup_printf("\n%s::%s()\n%s{\n\t\n}\n",
778 class_info->class_name, class_info->class_name, base_constructor);
779 g_free(base_constructor);
781 else
783 class_info->constructor_decl = g_strdup("");
784 class_info->constructor_impl = g_strdup("");
786 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_destructor_box)))
788 class_info->destructor_decl =
789 g_strdup_printf("virtual ~%s();\n", class_info->class_name);
790 class_info->destructor_impl = g_strdup_printf("\n%s::~%s()\n{\n\t\n}\n",
791 class_info->class_name, class_info->class_name);
793 else
795 class_info->destructor_decl = g_strdup("");
796 class_info->destructor_impl = g_strdup("");
798 break;
800 case GEANY_CLASS_TYPE_GTK:
802 class_info->namespace = g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg->class_namespace_entry)));
803 if (!NZV(class_info->namespace))
805 class_info->namespace_up = g_strdup("");
806 class_info->namespace_low = g_strdup("");
808 else
810 gchar *tmp_namespace;
811 gchar *tmp_namespace_split;
813 tmp_namespace_split = str_case_split(class_info->namespace, '_');
814 tmp_namespace = g_strconcat(tmp_namespace_split, "_", NULL);
815 class_info->namespace_up = g_ascii_strup(tmp_namespace, -1);
816 class_info->namespace_low = g_ascii_strdown(class_info->namespace_up, -1);
817 g_free(tmp_namespace);
818 g_free(tmp_namespace_split);
820 class_info->base_gtype = g_strdup(gtk_entry_get_text(
821 GTK_ENTRY(cc_dlg->base_gtype_entry)));
822 class_info->source = g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg->source_entry)));
823 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_constructor_box)))
825 class_info->constructor_decl = g_strdup_printf("%s*\t%s%s_new\t\t\t(void);\n",
826 gtk_entry_get_text(GTK_ENTRY(cc_dlg->gtk_constructor_type_entry)),
827 class_info->namespace_low, class_info->class_name_low);
828 class_info->constructor_impl = g_strdup_printf("\n"
829 "%s *%s%s_new(void)\n"
830 "{\n"
831 "\treturn g_object_new(%sTYPE_%s, NULL);\n"
832 "}\n",
833 gtk_entry_get_text(GTK_ENTRY(cc_dlg->gtk_constructor_type_entry)),
834 class_info->namespace_low, class_info->class_name_low,
835 class_info->namespace_up, class_info->class_name_up);
837 else
839 class_info->constructor_decl = g_strdup("");
840 class_info->constructor_impl = g_strdup("");
842 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_destructor_box)))
844 class_info->gtk_destructor_registration =
845 g_strdup_printf("GObjectClass *g_object_class;\n\n"
846 "\tg_object_class = G_OBJECT_CLASS(klass);\n\n"
847 "\tg_object_class->finalize = %s%s_finalize;\n",
848 class_info->namespace_low, class_info->class_name_low);
849 class_info->destructor_decl =
850 g_strdup_printf("static void %s%s_finalize\t\t\t(GObject *object);\n",
851 class_info->namespace_low, class_info->class_name_low);
852 class_info->destructor_impl = g_strdup_printf("\n"
853 "static void %s%s_finalize(GObject *object)\n"
854 "{\n"
855 "\t%s%s *self;\n\n"
856 "\tg_return_if_fail(object != NULL);\n"
857 "\tg_return_if_fail(%sIS_%s(object));\n\n"
858 "\tself = %s%s(object);\n\n"
859 "\tG_OBJECT_CLASS(%s%s_parent_class)->finalize(object);\n"
860 "}\n",
861 class_info->namespace_low, class_info->class_name_low,
862 class_info->namespace, class_info->class_name,
863 class_info->namespace_up, class_info->class_name_up,
864 class_info->namespace_up, class_info->class_name_up,
865 class_info->namespace_low, class_info->class_name_low);
867 else
869 class_info->gtk_destructor_registration = g_strdup("");
870 class_info->destructor_decl = g_strdup("");
871 class_info->destructor_impl = g_strdup("");
873 break;
875 case GEANY_CLASS_TYPE_PHP:
877 const gchar *tmp_str;
879 class_info->source = g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg->source_entry)));
881 tmp_str = gtk_entry_get_text(GTK_ENTRY(cc_dlg->class_namespace_entry));
882 if (! utils_str_equal(tmp_str, ""))
883 class_info->namespace_decl = g_strdup_printf("namespace %s;", tmp_str);
884 else
885 class_info->namespace_decl = g_strdup("");
887 tmp_str = gtk_entry_get_text(GTK_ENTRY(cc_dlg->class_implements_entry));
888 if (! utils_str_equal(tmp_str, ""))
889 class_info->implements_decl = g_strdup_printf(" implements %s", tmp_str);
890 else
891 class_info->implements_decl = g_strdup("");
893 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_constructor_box)) &&
894 ! gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_isabstract_box)))
896 class_info->constructor_impl = g_strdup_printf("\n"
897 "\t/**\n"
898 "\t * Constructor of class %s.\n"
899 "\t *\n"
900 "\t * @return void\n"
901 "\t */\n"
902 "\tpublic function __construct()\n"
903 "\t{\n"
904 "\t\t// ...\n"
905 "\t}\n",
906 class_info->class_name);
908 else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_constructor_box)) &&
909 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_isabstract_box)))
911 class_info->constructor_impl = g_strdup_printf("\n"
912 "\t/**\n"
913 "\t * Constructor of class %s.\n"
914 "\t *\n"
915 "\t * @return void\n"
916 "\t */\n"
917 "\tprotected function __construct()\n"
918 "\t{\n"
919 "\t\t// ...\n"
920 "\t}\n",
921 class_info->class_name);
923 else
924 class_info->constructor_impl = g_strdup("");
926 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_destructor_box)))
928 class_info->destructor_impl = g_strdup_printf("\n"
929 "\t/**\n"
930 "\t * Destructor of class %s.\n"
931 "\t *\n"
932 "\t * @return void\n"
933 "\t */\n"
934 "\tpublic function __destruct()\n"
935 "\t{\n"
936 "\t\t// ...\n"
937 "\t}\n",
938 class_info->class_name);
940 else
941 class_info->destructor_impl = g_strdup("");
943 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_isabstract_box)))
944 class_info->abstract_decl = g_strdup("abstract ");
945 else
946 class_info->abstract_decl = g_strdup("");
948 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_issingleton_box)))
950 class_info->singleton_impl = g_strdup_printf("\n"
951 "\t/**\n"
952 "\t * Holds instance of self.\n"
953 "\t * \n"
954 "\t * @var %s\n"
955 "\t */\n"
956 "\tprotected static $kInstance = null;\n\n"
957 "\t/**\n"
958 "\t * Returns instance of self.\n"
959 "\t * \n"
960 "\t * @return %s\n"
961 "\t */\n"
962 "\tpublic static function getInstance() {\n"
963 "\t\tif(!(self::$kInstance instanceof %s)) {\n"
964 "\t\t\tself::$kInstance = new self();\n"
965 "\t\t}\n"
966 "\t\treturn self::$kInstance;\n"
967 "\t}\n",
968 class_info->class_name,
969 class_info->class_name,
970 class_info->class_name);
972 else
973 class_info->singleton_impl = g_strdup("");
974 break;
978 /* only create the files if the filename is not empty */
979 if (! utils_str_equal(class_info->source, ""))
981 text = get_template_class_source(class_info);
982 doc = document_new_file(class_info->source, NULL, NULL);
983 editor_insert_text_block(doc->editor, text, 0, -1, 0, TRUE);
984 g_free(text);
987 if (! utils_str_equal(class_info->header, "") && class_info->type != GEANY_CLASS_TYPE_PHP)
989 text = get_template_class_header(class_info);
990 doc = document_new_file(class_info->header, NULL, NULL);
991 editor_insert_text_block(doc->editor, text, 0, -1, 0, TRUE);
992 g_free(text);
995 free_pointers(24, tmp, class_info->namespace, class_info->namespace_up,
996 class_info->namespace_low, class_info->class_name, class_info->class_name_up,
997 class_info->base_name, class_info->class_name_low, class_info->base_include,
998 class_info->header, class_info->header_guard, class_info->source, class_info->base_decl,
999 class_info->constructor_decl, class_info->constructor_impl,
1000 class_info->gtk_destructor_registration, class_info->destructor_decl,
1001 class_info->destructor_impl, class_info->base_gtype,
1002 class_info->namespace_decl, class_info->implements_decl,
1003 class_info->abstract_decl, class_info->singleton_impl, class_info, NULL);
1004 return TRUE;
1008 static void
1009 on_menu_create_cpp_class_activate (GtkMenuItem *menuitem,
1010 gpointer user_data)
1012 show_dialog_create_class(GEANY_CLASS_TYPE_CPP);
1016 static void
1017 on_menu_create_gtk_class_activate (GtkMenuItem *menuitem,
1018 gpointer user_data)
1020 show_dialog_create_class(GEANY_CLASS_TYPE_GTK);
1024 static void
1025 on_menu_create_php_class_activate (GtkMenuItem *menuitem,
1026 gpointer user_data)
1028 show_dialog_create_class(GEANY_CLASS_TYPE_PHP);
1032 void plugin_init(GeanyData *data)
1034 GtkWidget *menu_create_class1;
1035 GtkWidget *menu_create_class1_menu;
1036 GtkWidget *menu_create_cpp_class;
1037 GtkWidget *menu_create_gtk_class;
1038 GtkWidget *menu_create_php_class;
1040 menu_create_class1 = ui_image_menu_item_new (GTK_STOCK_ADD, _("Create Cla_ss"));
1041 gtk_container_add (GTK_CONTAINER (geany->main_widgets->tools_menu), menu_create_class1);
1043 menu_create_class1_menu = gtk_menu_new ();
1044 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_create_class1), menu_create_class1_menu);
1046 menu_create_cpp_class = gtk_menu_item_new_with_mnemonic (_("_C++ Class"));
1047 gtk_container_add (GTK_CONTAINER (menu_create_class1_menu), menu_create_cpp_class);
1049 menu_create_gtk_class = gtk_menu_item_new_with_mnemonic (_("_GTK+ Class"));
1050 gtk_container_add (GTK_CONTAINER (menu_create_class1_menu), menu_create_gtk_class);
1052 menu_create_php_class = gtk_menu_item_new_with_mnemonic (_("_PHP Class"));
1053 gtk_container_add (GTK_CONTAINER (menu_create_class1_menu), menu_create_php_class);
1055 g_signal_connect(menu_create_cpp_class, "activate",
1056 G_CALLBACK (on_menu_create_cpp_class_activate),
1057 NULL);
1058 g_signal_connect(menu_create_gtk_class, "activate",
1059 G_CALLBACK (on_menu_create_gtk_class_activate),
1060 NULL);
1061 g_signal_connect(menu_create_php_class, "activate",
1062 G_CALLBACK (on_menu_create_php_class_activate),
1063 NULL);
1065 gtk_widget_show_all(menu_create_class1);
1067 main_menu_item = menu_create_class1;
1071 void plugin_cleanup(void)
1073 gtk_widget_destroy(main_menu_item);