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,
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
;
50 typedef struct _ClassInfo ClassInfo
;
60 gchar
*class_name_low
;
67 gchar
*constructor_decl
;
68 gchar
*destructor_decl
;
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
;
77 gchar
*singleton_impl
;
80 typedef struct _CreateClassDialog
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
;
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\
107 class {class_name}{base_decl}\n\
114 /* add your private declarations */\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\
127 static const gchar templates_gtk_class_header
[] = "{fileheader}\n\n\
128 #ifndef __{header_guard}__\n\
129 #define __{header_guard}__\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\
151 {base_name} parent;\n\
152 /* add your public declarations here */\n\
154 {namespace}{class_name}Private *priv;\n\
157 struct _{namespace}{class_name}Class\n\
159 {base_name}Class parent_class;\n\
162 GType {namespace_low}{class_name_low}_get_type (void);\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\
175 /* add your private declarations here */\n\
180 G_DEFINE_TYPE({namespace}{class_name}, {namespace_low}{class_name_low}, {base_gtype})\n\
182 static void {namespace_low}{class_name_low}_class_init({namespace}{class_name}Class *klass)\n\
184 {gtk_destructor_registration}\n\
185 g_type_class_add_private((gpointer)klass, sizeof({namespace}{class_name}Private));\n\
190 static void {namespace_low}{class_name_low}_init({namespace}{class_name} *self)\n\
192 self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self,\n\
193 {namespace_up}TYPE_{class_name_up}, {namespace}{class_name}Private);\n\
197 {constructor_impl}\n\
200 static const gchar templates_php_class_source
[] = "<?php\n\
204 {abstract_decl}class {class_name}{base_decl}{implements_decl}\n\{\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. */
222 free_pointers(gsize arg_count
, ...)
228 va_start(a
, arg_count
);
229 for (i
= 0; i
< arg_count
; i
++)
231 ptr
= va_arg(a
, gpointer
);
234 ptr
= va_arg(a
, gpointer
);
236 g_warning("Wrong arg_count!");
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
);
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
);
284 return g_string_free(template, FALSE
);
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
);
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
);
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
);
353 return g_string_free(template, FALSE
);
359 void show_dialog_create_class(gint type
)
361 CreateClassDialog
*cc_dlg
;
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
),
375 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
376 GTK_STOCK_OK
, GTK_RESPONSE_OK
,
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:"));
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
))
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
)
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
);
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
);
603 case GEANY_CLASS_TYPE_PHP
:
606 class_source
= g_strconcat(class_name
, ".php", NULL
);
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
);
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
)
641 g_return_val_if_fail(str
!= NULL
, NULL
);
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
;
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
);
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
);
682 base_header
= g_ascii_strdown(tmp
, -1);
686 gtk_entry_set_text(GTK_ENTRY(cc_dlg
->base_header_entry
), base_header
);
688 if (cc_dlg
->class_type
== GEANY_CLASS_TYPE_GTK
)
691 if (! g_ascii_strncasecmp(gtk_entry_get_text(GTK_ENTRY(entry
)), "gtk", 3))
692 tmp
= g_strdup_printf("%.3s_TYPE%s",
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");
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
);
706 g_free(base_name_splitted
);
711 static gboolean
create_class(CreateClassDialog
*cc_dlg
)
713 ClassInfo
*class_info
;
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
)), ""))
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
)) ?
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
)) ?
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
);
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
);
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("");
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
);
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
);
795 class_info
->destructor_decl
= g_strdup("");
796 class_info
->destructor_impl
= g_strdup("");
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("");
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"
831 "\treturn g_object_new(%sTYPE_%s, NULL);\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
);
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"
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"
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
);
869 class_info
->gtk_destructor_registration
= g_strdup("");
870 class_info
->destructor_decl
= g_strdup("");
871 class_info
->destructor_impl
= g_strdup("");
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
);
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
);
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"
898 "\t * Constructor of class %s.\n"
900 "\t * @return void\n"
902 "\tpublic function __construct()\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"
913 "\t * Constructor of class %s.\n"
915 "\t * @return void\n"
917 "\tprotected function __construct()\n"
921 class_info
->class_name
);
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"
930 "\t * Destructor of class %s.\n"
932 "\t * @return void\n"
934 "\tpublic function __destruct()\n"
938 class_info
->class_name
);
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 ");
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"
952 "\t * Holds instance of self.\n"
956 "\tprotected static $kInstance = null;\n\n"
958 "\t * Returns instance of self.\n"
962 "\tpublic static function getInstance() {\n"
963 "\t\tif(!(self::$kInstance instanceof %s)) {\n"
964 "\t\t\tself::$kInstance = new self();\n"
966 "\t\treturn self::$kInstance;\n"
968 class_info
->class_name
,
969 class_info
->class_name
,
970 class_info
->class_name
);
973 class_info
->singleton_impl
= g_strdup("");
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
);
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
);
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
);
1009 on_menu_create_cpp_class_activate (GtkMenuItem
*menuitem
,
1012 show_dialog_create_class(GEANY_CLASS_TYPE_CPP
);
1017 on_menu_create_gtk_class_activate (GtkMenuItem
*menuitem
,
1020 show_dialog_create_class(GEANY_CLASS_TYPE_GTK
);
1025 on_menu_create_php_class_activate (GtkMenuItem
*menuitem
,
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
),
1058 g_signal_connect(menu_create_gtk_class
, "activate",
1059 G_CALLBACK (on_menu_create_gtk_class_activate
),
1061 g_signal_connect(menu_create_php_class
, "activate",
1062 G_CALLBACK (on_menu_create_php_class_activate
),
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
);