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-2012 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
6 * Copyright 2007-2012 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 along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 /* Class Builder - creates source files containing a new class interface and definition. */
29 #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, Ondrej Donek, the Geany developer team")
41 static GtkWidget
*main_menu_item
= NULL
;
51 typedef struct _ClassInfo ClassInfo
;
61 gchar
*class_name_low
;
68 gchar
*constructor_decl
;
69 gchar
*destructor_decl
;
71 gchar
*constructor_impl
;
72 gchar
*destructor_impl
;
73 gchar
*gtk_destructor_registration
;
74 /* These are needed only for PHP classes */
75 gchar
*namespace_decl
;
76 gchar
*implements_decl
;
78 gchar
*singleton_impl
;
81 typedef struct _CreateClassDialog
85 GtkWidget
*class_name_entry
;
86 GtkWidget
*header_entry
;
87 GtkWidget
*source_entry
;
88 GtkWidget
*base_name_entry
;
89 GtkWidget
*base_header_entry
;
90 GtkWidget
*base_header_global_box
;
91 GtkWidget
*base_gtype_entry
;
92 GtkWidget
*create_constructor_box
;
93 GtkWidget
*create_destructor_box
;
94 GtkWidget
*gtk_constructor_type_entry
;
95 /* These are needed only for PHP classes */
96 GtkWidget
*class_namespace_entry
;
97 GtkWidget
*class_implements_entry
;
98 GtkWidget
*create_isabstract_box
;
99 GtkWidget
*create_issingleton_box
;
103 /* TODO make these templates configurable */
104 static const gchar templates_cpp_class_header
[] = "{fileheader}\n\n\
105 #ifndef {header_guard}\n\
106 #define {header_guard}\n\
108 class {class_name}{base_decl}\n\
115 /* add your private declarations */\n\
118 #endif /* {header_guard} */ \n\
121 static const gchar templates_cpp_class_source
[] = "{fileheader}\n\n\
122 #include \"{header}\"\n\
124 {constructor_impl}\n\
128 static const gchar templates_gtk_class_header
[] = "{fileheader}\n\n\
129 #ifndef {header_guard}_\n\
130 #define {header_guard}_ 1\n\
134 #define {namespace_up}TYPE_{class_name_up} ({namespace_low}{class_name_low}_get_type ())\n\
135 #define {namespace_up}{class_name_up}(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), {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), {namespace_up}TYPE_{class_name_up}, {namespace}{class_name}Class))\n\
137 #define {namespace_up}IS_{class_name_up}(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), {namespace_up}TYPE_{class_name_up}))\n\
138 #define {namespace_up}IS_{class_name_up}_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), {namespace_up}TYPE_{class_name_up}))\n\
139 #define {namespace_up}{class_name_up}_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), {namespace_up}TYPE_{class_name_up}, {namespace}{class_name}Class))\n\
141 typedef struct {namespace}{class_name}_ {namespace}{class_name};\n\
142 typedef struct {namespace}{class_name}Class_ {namespace}{class_name}Class;\n\
143 typedef struct {namespace}{class_name}Private_ {namespace}{class_name}Private;\n\
145 struct {namespace}{class_name}_\n\
147 {base_name} parent;\n\
148 /* add your public declarations here */\n\
149 {namespace}{class_name}Private *priv;\n\
152 struct {namespace}{class_name}Class_\n\
154 {base_name}Class parent_class;\n\
157 GType {namespace_low}{class_name_low}_get_type (void);\n\n\
162 #endif /* {header_guard}_ */\n\
165 static const gchar templates_gtk_class_source
[] = "{fileheader}\n\
166 #include \"{header}\"\n\
168 struct {namespace}{class_name}Private_\n\
170 /* add your private declarations here */\n\
171 gpointer delete_me;\n\
176 G_DEFINE_TYPE ({namespace}{class_name}, {namespace_low}{class_name_low}, {base_gtype})\n\
179 {namespace_low}{class_name_low}_class_init ({namespace}{class_name}Class *klass)\n\
181 {gtk_destructor_registration}\n\
182 g_type_class_add_private ((gpointer)klass, sizeof ({namespace}{class_name}Private));\n\
188 {namespace_low}{class_name_low}_init ({namespace}{class_name} *self)\n\
190 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, {namespace_up}TYPE_{class_name_up}, {namespace}{class_name}Private);\n\
193 {constructor_impl}\n\
196 static const gchar templates_php_class_source
[] = "<?php\n\
200 {abstract_decl}class {class_name}{base_decl}{implements_decl}\n{\n\
209 static void cc_dlg_on_set_sensitive_toggled(GtkWidget
*toggle_button
, GtkWidget
*target_widget
);
210 static void cc_dlg_on_class_name_entry_changed(GtkWidget
*entry
, CreateClassDialog
*cc_dlg
);
211 static void cc_dlg_on_class_namespace_entry_changed(GtkWidget
*entry
, CreateClassDialog
*cc_dlg
);
212 static void cc_dlg_on_base_name_entry_changed(GtkWidget
*entry
, CreateClassDialog
*cc_dlg
);
213 static gboolean
create_class(CreateClassDialog
*cc_dlg
);
216 /* The list must be ended with NULL as an extra check that arg_count is correct. */
218 free_pointers(gsize arg_count
, ...)
224 va_start(a
, arg_count
);
225 for (i
= 0; i
< arg_count
; i
++)
227 ptr
= va_arg(a
, gpointer
);
230 ptr
= va_arg(a
, gpointer
);
232 g_warning("Wrong arg_count!");
238 get_template_class_header(ClassInfo
*class_info
)
240 gchar
*fileheader
= NULL
;
241 GString
*template = NULL
;
243 switch (class_info
->type
)
245 case GEANY_CLASS_TYPE_CPP
:
246 fileheader
= templates_get_template_fileheader(GEANY_FILETYPES_CPP
, class_info
->header
);
247 template = g_string_new(templates_cpp_class_header
);
248 utils_string_replace_all(template, "{fileheader}", fileheader
);
249 utils_string_replace_all(template, "{header_guard}", class_info
->header_guard
);
250 utils_string_replace_all(template, "{base_include}", class_info
->base_include
);
251 utils_string_replace_all(template, "{class_name}", class_info
->class_name
);
252 utils_string_replace_all(template, "{base_decl}", class_info
->base_decl
);
253 utils_string_replace_all(template, "{constructor_decl}",
254 class_info
->constructor_decl
);
255 utils_string_replace_all(template, "{destructor_decl}",
256 class_info
->destructor_decl
);
259 case GEANY_CLASS_TYPE_GTK
:
260 fileheader
= templates_get_template_fileheader(GEANY_FILETYPES_C
, class_info
->header
);
261 template = g_string_new(templates_gtk_class_header
);
262 utils_string_replace_all(template, "{fileheader}", fileheader
);
263 utils_string_replace_all(template, "{header_guard}", class_info
->header_guard
);
264 utils_string_replace_all(template, "{base_include}", class_info
->base_include
);
265 utils_string_replace_all(template, "{namespace}", class_info
->namespace);
266 utils_string_replace_all(template, "{namespace_up}", class_info
->namespace_up
);
267 utils_string_replace_all(template, "{namespace_low}", class_info
->namespace_low
);
268 utils_string_replace_all(template, "{class_name}", class_info
->class_name
);
269 utils_string_replace_all(template, "{class_name_up}", class_info
->class_name_up
);
270 utils_string_replace_all(template, "{class_name_low}", class_info
->class_name_low
);
271 utils_string_replace_all(template, "{base_name}", class_info
->base_name
);
272 utils_string_replace_all(template, "{constructor_decl}",
273 class_info
->constructor_decl
);
280 return g_string_free(template, FALSE
);
287 get_template_class_source(ClassInfo
*class_info
)
289 gchar
*fileheader
= NULL
;
290 GString
*template = NULL
;
292 switch (class_info
->type
)
294 case GEANY_CLASS_TYPE_CPP
:
295 fileheader
= templates_get_template_fileheader(GEANY_FILETYPES_CPP
, class_info
->source
);
296 template = g_string_new(templates_cpp_class_source
);
297 utils_string_replace_all(template, "{fileheader}", fileheader
);
298 utils_string_replace_all(template, "{header}", class_info
->header
);
299 utils_string_replace_all(template, "{class_name}", class_info
->class_name
);
300 utils_string_replace_all(template, "{base_include}", class_info
->base_include
);
301 utils_string_replace_all(template, "{base_name}", class_info
->base_name
);
302 utils_string_replace_all(template, "{constructor_impl}",
303 class_info
->constructor_impl
);
304 utils_string_replace_all(template, "{destructor_impl}",
305 class_info
->destructor_impl
);
308 case GEANY_CLASS_TYPE_GTK
:
309 fileheader
= templates_get_template_fileheader(GEANY_FILETYPES_C
, class_info
->source
);
310 template = g_string_new(templates_gtk_class_source
);
311 utils_string_replace_all(template, "{fileheader}", fileheader
);
312 utils_string_replace_all(template, "{header}", class_info
->header
);
313 utils_string_replace_all(template, "{namespace}", class_info
->namespace);
314 utils_string_replace_all(template, "{namespace_up}", class_info
->namespace_up
);
315 utils_string_replace_all(template, "{namespace_low}", class_info
->namespace_low
);
316 utils_string_replace_all(template, "{class_name}", class_info
->class_name
);
317 utils_string_replace_all(template, "{class_name_up}", class_info
->class_name_up
);
318 utils_string_replace_all(template, "{class_name_low}", class_info
->class_name_low
);
319 utils_string_replace_all(template, "{base_name}", class_info
->base_name
);
320 utils_string_replace_all(template, "{base_gtype}", class_info
->base_gtype
);
321 utils_string_replace_all(template, "{destructor_decl}", class_info
->destructor_decl
);
322 utils_string_replace_all(template, "{constructor_impl}",
323 class_info
->constructor_impl
);
324 utils_string_replace_all(template, "{destructor_impl}",
325 class_info
->destructor_impl
);
326 utils_string_replace_all(template, "{gtk_destructor_registration}",
327 class_info
->gtk_destructor_registration
);
330 case GEANY_CLASS_TYPE_PHP
:
331 fileheader
= templates_get_template_fileheader(GEANY_FILETYPES_PHP
, class_info
->source
);
332 template = g_string_new(templates_php_class_source
);
333 utils_string_replace_all(template, "{fileheader}", fileheader
);
334 utils_string_replace_all(template, "{namespace_decl}", class_info
->namespace_decl
);
335 utils_string_replace_all(template, "{base_include}", class_info
->base_include
);
336 utils_string_replace_all(template, "{abstract_decl}", class_info
->abstract_decl
);
337 utils_string_replace_all(template, "{class_name}", class_info
->class_name
);
338 utils_string_replace_all(template, "{base_decl}", class_info
->base_decl
);
339 utils_string_replace_all(template, "{implements_decl}", class_info
->implements_decl
);
340 utils_string_replace_all(template, "{constructor_impl}", class_info
->constructor_impl
);
341 utils_string_replace_all(template, "{destructor_impl}", class_info
->destructor_impl
);
342 utils_string_replace_all(template, "{singleton_impl}", class_info
->singleton_impl
);
349 return g_string_free(template, FALSE
);
354 /* Creates a new option label, indented on the left */
355 static GtkWidget
*cc_option_label_new(const gchar
*text
)
360 align
= gtk_alignment_new(0.0, 0.5, 1.0, 1.0);
361 gtk_alignment_set_padding(GTK_ALIGNMENT(align
), 0, 0, 12, 0);
363 label
= gtk_label_new(text
);
364 gtk_misc_set_alignment(GTK_MISC(label
), 0.0, 0.5);
365 gtk_container_add(GTK_CONTAINER(align
), label
);
370 /* Attaches a new section label at the specified table row, optionally
371 * padded at the top, and returns the new label. */
372 static GtkWidget
*cc_table_attach_section_label(GtkWidget
*table
, const gchar
*text
,
373 guint row
, gboolean top_padding
)
376 GtkWidget
*label
, *align
;
378 label
= gtk_label_new(NULL
);
379 markup
= g_markup_printf_escaped("<b>%s</b>", text
);
380 gtk_label_set_markup(GTK_LABEL(label
), markup
);
382 gtk_misc_set_alignment(GTK_MISC(label
), 0.0, 0.5);
384 align
= gtk_alignment_new(0.0, 0.5, 1.0, 1.0);
386 gtk_alignment_set_padding(GTK_ALIGNMENT(align
), 6, 0, 0, 0);
387 gtk_container_add(GTK_CONTAINER(align
), label
);
389 gtk_table_attach(GTK_TABLE(table
), align
,
391 GTK_EXPAND
| GTK_FILL
, GTK_FILL
, 0, 0);
396 /* Attach a new option label at the specified table row and returns
398 static GtkWidget
*cc_table_attach_option_label(GtkWidget
*table
, const gchar
*text
, guint row
)
400 GtkWidget
*opt_label
= cc_option_label_new(text
);
401 gtk_table_attach(GTK_TABLE(table
), opt_label
,
403 GTK_FILL
|GTK_SHRINK
, GTK_FILL
|GTK_SHRINK
, 0, 0);
407 /* Attach an option label and entry to the table at the specified row.
408 * The label associated with the widget is set as data on the entry
409 * with the "label" key, if access to it is needed later. The entry
410 * widget is returned. */
411 static GtkWidget
*cc_table_attach_option_entry(GtkWidget
*table
, const gchar
*text
, guint row
)
415 label
= cc_table_attach_option_label(table
, text
, row
);
416 entry
= gtk_entry_new();
417 g_object_set_data(G_OBJECT(entry
), "label", label
);
418 gtk_table_attach(GTK_TABLE(table
), entry
,
420 GTK_EXPAND
|GTK_FILL
, GTK_FILL
, 0, 0);
424 static void show_dialog_create_class(gint type
)
426 CreateClassDialog
*cc_dlg
;
427 GtkWidget
*main_box
, *table
, *label
, *hdr_hbox
;
428 GtkWidget
*opt_table
, *align
;
431 cc_dlg
= g_new0(CreateClassDialog
, 1);
432 cc_dlg
->class_type
= type
;
434 cc_dlg
->dialog
= gtk_dialog_new_with_buttons(_("Create Class"),
435 GTK_WINDOW(geany
->main_widgets
->window
),
437 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
438 GTK_STOCK_OK
, GTK_RESPONSE_OK
,
440 gtk_dialog_set_has_separator(GTK_DIALOG(cc_dlg
->dialog
), TRUE
);
444 case GEANY_CLASS_TYPE_CPP
:
445 gtk_window_set_title(GTK_WINDOW(cc_dlg
->dialog
), _("Create C++ Class"));
447 case GEANY_CLASS_TYPE_GTK
:
448 gtk_window_set_title(GTK_WINDOW(cc_dlg
->dialog
), _("Create GTK+ Class"));
450 case GEANY_CLASS_TYPE_PHP
:
451 gtk_window_set_title(GTK_WINDOW(cc_dlg
->dialog
), _("Create PHP Class"));
455 g_signal_connect_swapped(cc_dlg
->dialog
, "destroy", G_CALLBACK(g_free
), (gpointer
)cc_dlg
);
457 table
= gtk_table_new(13, 2, FALSE
);
458 gtk_table_set_col_spacings(GTK_TABLE(table
), 6);
459 gtk_table_set_row_spacings(GTK_TABLE(table
), 6);
461 main_box
= ui_dialog_vbox_new(GTK_DIALOG(cc_dlg
->dialog
));
462 gtk_box_pack_start(GTK_BOX(main_box
), table
, TRUE
, TRUE
, 0);
466 if (type
== GEANY_CLASS_TYPE_PHP
|| type
== GEANY_CLASS_TYPE_GTK
)
468 cc_table_attach_section_label(table
, _("Namespace"), row
++, FALSE
);
469 cc_dlg
->class_namespace_entry
= cc_table_attach_option_entry(table
, _("Name:"), row
++);
470 g_signal_connect(cc_dlg
->class_namespace_entry
, "changed",
471 G_CALLBACK(cc_dlg_on_class_namespace_entry_changed
), cc_dlg
);
474 if (type
== GEANY_CLASS_TYPE_PHP
|| type
== GEANY_CLASS_TYPE_GTK
)
475 cc_table_attach_section_label(table
, _("Class"), row
++, TRUE
);
477 cc_table_attach_section_label(table
, _("Class"), row
++, FALSE
);
479 cc_dlg
->class_name_entry
= cc_table_attach_option_entry(table
, _("Name:"), row
++);
480 g_signal_connect(cc_dlg
->class_name_entry
, "changed",
481 G_CALLBACK(cc_dlg_on_class_name_entry_changed
), cc_dlg
);
483 if (type
!= GEANY_CLASS_TYPE_PHP
)
484 cc_dlg
->header_entry
= cc_table_attach_option_entry(table
, _("Header file:"), row
++);
486 cc_dlg
->source_entry
= cc_table_attach_option_entry(table
, _("Source file:"), row
++);
488 cc_table_attach_section_label(table
, _("Inheritance"), row
++, TRUE
);
490 cc_dlg
->base_name_entry
= cc_table_attach_option_entry(table
, _("Base class:"), row
++);
492 if (type
== GEANY_CLASS_TYPE_GTK
)
493 gtk_entry_set_text(GTK_ENTRY(cc_dlg
->base_name_entry
), "GObject");
494 g_signal_connect(cc_dlg
->base_name_entry
, "changed",
495 G_CALLBACK(cc_dlg_on_base_name_entry_changed
), (gpointer
)cc_dlg
);
497 if (type
== GEANY_CLASS_TYPE_PHP
)
498 cc_dlg
->base_header_entry
= cc_table_attach_option_entry(table
, _("Base source:"), row
++);
501 hdr_hbox
= gtk_hbox_new(FALSE
, 6);
503 label
= cc_table_attach_option_label(table
, _("Base header:"), row
);
505 cc_dlg
->base_header_entry
= gtk_entry_new();
506 g_object_set_data(G_OBJECT(cc_dlg
->base_header_entry
), "label", label
);
507 gtk_box_pack_start(GTK_BOX(hdr_hbox
),
508 cc_dlg
->base_header_entry
,
511 cc_dlg
->base_header_global_box
= gtk_check_button_new_with_label(_("Global"));
512 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cc_dlg
->base_header_global_box
), TRUE
);
513 gtk_box_pack_start(GTK_BOX(hdr_hbox
),
514 cc_dlg
->base_header_global_box
,
517 gtk_table_attach(GTK_TABLE(table
), hdr_hbox
,
519 GTK_FILL
| GTK_EXPAND
,
520 GTK_FILL
| GTK_EXPAND
,
525 if (type
== GEANY_CLASS_TYPE_GTK
)
526 gtk_entry_set_text(GTK_ENTRY(cc_dlg
->base_header_entry
), "glib-object.h");
528 if (type
== GEANY_CLASS_TYPE_GTK
)
530 cc_dlg
->base_gtype_entry
= cc_table_attach_option_entry(table
, _("Base GType:"), row
++);
531 gtk_entry_set_text(GTK_ENTRY(cc_dlg
->base_gtype_entry
), "G_TYPE_OBJECT");
534 if (type
== GEANY_CLASS_TYPE_PHP
)
535 cc_dlg
->class_implements_entry
= cc_table_attach_option_entry(table
, _("Implements:"), row
++);
537 cc_table_attach_section_label(table
, _("Options"), row
++, TRUE
);
539 align
= gtk_alignment_new(0.0, 0.5, 1.0, 1.0);
540 gtk_alignment_set_padding(GTK_ALIGNMENT(align
), 0, 0, 12, 0);
542 opt_table
= gtk_table_new(1, 2, FALSE
);
543 gtk_table_set_row_spacings(GTK_TABLE(opt_table
), 6);
544 gtk_table_set_col_spacings(GTK_TABLE(opt_table
), 6);
545 gtk_container_add(GTK_CONTAINER(align
), opt_table
);
547 gtk_table_attach(GTK_TABLE(table
), align
,
554 cc_dlg
->create_constructor_box
= gtk_check_button_new_with_label(_("Create constructor"));
555 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cc_dlg
->create_constructor_box
), TRUE
);
556 gtk_table_attach(GTK_TABLE(opt_table
), cc_dlg
->create_constructor_box
,
557 0, 1, 0, 1, GTK_FILL
|GTK_SHRINK
, GTK_FILL
|GTK_SHRINK
, 0, 0);
559 cc_dlg
->create_destructor_box
= gtk_check_button_new_with_label(_("Create destructor"));
560 gtk_table_attach(GTK_TABLE(opt_table
), cc_dlg
->create_destructor_box
,
561 1, 2, 0, 1, GTK_FILL
|GTK_SHRINK
, GTK_FILL
|GTK_SHRINK
, 0, 0);
563 if (type
== GEANY_CLASS_TYPE_PHP
)
565 gtk_table_resize(GTK_TABLE(opt_table
), 2, 2);
566 cc_dlg
->create_isabstract_box
= gtk_check_button_new_with_label(_("Is abstract"));
567 gtk_table_attach(GTK_TABLE(opt_table
), cc_dlg
->create_isabstract_box
,
568 0, 1, 1, 2, GTK_FILL
|GTK_SHRINK
, GTK_FILL
|GTK_SHRINK
, 0, 0);
569 cc_dlg
->create_issingleton_box
= gtk_check_button_new_with_label(_("Is singleton"));
570 gtk_table_attach(GTK_TABLE(opt_table
), cc_dlg
->create_issingleton_box
,
571 1, 2, 1, 2, GTK_FILL
|GTK_SHRINK
, GTK_FILL
|GTK_SHRINK
, 0, 0);
574 gtk_widget_show_all(align
);
576 if (type
== GEANY_CLASS_TYPE_GTK
)
578 cc_dlg
->gtk_constructor_type_entry
= cc_table_attach_option_entry(table
,
579 _("Constructor type:"), row
++);
580 gtk_entry_set_text(GTK_ENTRY(cc_dlg
->gtk_constructor_type_entry
), "GObject");
581 g_signal_connect(cc_dlg
->create_constructor_box
, "toggled",
582 G_CALLBACK(cc_dlg_on_set_sensitive_toggled
),
583 cc_dlg
->gtk_constructor_type_entry
);
585 else if (type
== GEANY_CLASS_TYPE_PHP
)
586 gtk_table_resize(GTK_TABLE(table
), row
, 2);
587 else if (type
== GEANY_CLASS_TYPE_CPP
)
588 gtk_table_resize(GTK_TABLE(table
), row
, 2);
590 gtk_widget_show_all(cc_dlg
->dialog
);
591 while (gtk_dialog_run(GTK_DIALOG(cc_dlg
->dialog
)) == GTK_RESPONSE_OK
)
593 if (create_class(cc_dlg
))
598 gtk_widget_destroy(cc_dlg
->dialog
);
602 static void cc_dlg_on_set_sensitive_toggled(GtkWidget
*toggle_button
, GtkWidget
*target_widget
)
606 g_return_if_fail(toggle_button
!= NULL
);
607 g_return_if_fail(GTK_IS_TOGGLE_BUTTON(toggle_button
));
608 g_return_if_fail(target_widget
!= NULL
);
609 g_return_if_fail(GTK_IS_WIDGET(target_widget
));
611 label
= g_object_get_data(G_OBJECT(target_widget
), "label");
613 gtk_widget_set_sensitive(target_widget
,
614 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle_button
)));
615 gtk_widget_set_sensitive(label
,
616 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle_button
)));
620 static void cc_dlg_update_file_names(CreateClassDialog
*cc_dlg
)
623 gchar
*class_name_down
;
624 gchar
*class_header
= NULL
;
625 gchar
*class_source
= NULL
;
627 g_return_if_fail(cc_dlg
!= NULL
);
629 class_name
= g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg
->class_name_entry
)));
630 class_name_down
= g_ascii_strdown(class_name
, -1);
631 switch (cc_dlg
->class_type
)
633 case GEANY_CLASS_TYPE_CPP
:
635 class_header
= g_strconcat(class_name_down
, ".h", NULL
);
636 class_source
= g_strconcat(class_name_down
, ".cpp", NULL
);
639 case GEANY_CLASS_TYPE_GTK
:
641 const gchar
*namespace;
642 gchar
*namespace_down
;
644 namespace = gtk_entry_get_text(GTK_ENTRY(cc_dlg
->class_namespace_entry
));
645 namespace_down
= g_ascii_strdown(namespace, -1);
646 class_header
= g_strconcat(namespace_down
, class_name_down
, ".h", NULL
);
647 class_source
= g_strconcat(namespace_down
, class_name_down
, ".c", NULL
);
648 g_free(namespace_down
);
651 case GEANY_CLASS_TYPE_PHP
:
654 class_source
= g_strconcat(class_name
, ".php", NULL
);
659 if (cc_dlg
->header_entry
!= NULL
&& class_header
!= NULL
)
660 gtk_entry_set_text(GTK_ENTRY(cc_dlg
->header_entry
), class_header
);
661 if (cc_dlg
->source_entry
!= NULL
&& class_source
!= NULL
)
662 gtk_entry_set_text(GTK_ENTRY(cc_dlg
->source_entry
), class_source
);
665 g_free(class_name_down
);
666 g_free(class_header
);
667 g_free(class_source
);
671 static void cc_dlg_on_class_name_entry_changed(GtkWidget
*entry
, CreateClassDialog
*cc_dlg
)
673 cc_dlg_update_file_names(cc_dlg
);
677 static void cc_dlg_on_class_namespace_entry_changed(GtkWidget
*entry
, CreateClassDialog
*cc_dlg
)
680 if (cc_dlg
->class_type
== GEANY_CLASS_TYPE_GTK
)
681 cc_dlg_update_file_names(cc_dlg
);
685 static gchar
* str_case_split(const gchar
*str
, gchar splitter
)
689 g_return_val_if_fail(str
!= NULL
, NULL
);
693 result
= g_string_new(NULL
);
694 g_string_append_c(result
, *str
);
695 while (*(++str
) != '\0')
697 if (g_ascii_isupper(*str
) && g_ascii_islower(result
->str
[result
->len
- 1]))
698 g_string_append_c(result
, splitter
);
699 g_string_append_c(result
, *str
);
701 return g_string_free(result
, FALSE
);
705 static void cc_dlg_on_base_name_entry_changed(GtkWidget
*entry
, CreateClassDialog
*cc_dlg
)
707 gchar
*base_name_splitted
;
711 g_return_if_fail(entry
!= NULL
);
712 g_return_if_fail(GTK_IS_ENTRY(entry
));
713 g_return_if_fail(cc_dlg
!= NULL
);
715 base_name_splitted
= str_case_split(gtk_entry_get_text(GTK_ENTRY(entry
)), '_');
716 if (! g_ascii_strncasecmp(gtk_entry_get_text(GTK_ENTRY(entry
)), "gtk", 3))
717 /*tmp = g_strconcat("gtk/", gtk_entry_get_text(GTK_ENTRY(entry)), ".h", NULL);*/
718 /* With GTK 2.14 (and later GTK 3), single header includes are encouraged */
719 tmp
= g_strdup("gtk/gtk.h");
720 else if (utils_str_equal(gtk_entry_get_text(GTK_ENTRY(entry
)), "GObject"))
721 tmp
= g_strdup("glib-object.h");
722 else if (cc_dlg
->class_type
== GEANY_CLASS_TYPE_PHP
)
723 tmp
= g_strconcat(gtk_entry_get_text(GTK_ENTRY(entry
)), ".php", NULL
);
725 tmp
= g_strconcat(gtk_entry_get_text(GTK_ENTRY(entry
)), ".h", NULL
);
727 if (cc_dlg
->class_type
== GEANY_CLASS_TYPE_PHP
)
728 base_header
= g_strdup(tmp
);
730 base_header
= g_ascii_strdown(tmp
, -1);
734 gtk_entry_set_text(GTK_ENTRY(cc_dlg
->base_header_entry
), base_header
);
736 if (cc_dlg
->class_type
== GEANY_CLASS_TYPE_GTK
)
739 if (! g_ascii_strncasecmp(gtk_entry_get_text(GTK_ENTRY(entry
)), "gtk", 3))
740 tmp
= g_strdup_printf("%.3s_TYPE%s",
742 base_name_splitted
+ 3);
743 else if (utils_str_equal(gtk_entry_get_text(GTK_ENTRY(entry
)), "GObject"))
744 tmp
= g_strdup("G_TYPE_OBJECT");
746 tmp
= g_strconcat(base_name_splitted
, "_TYPE", NULL
);
747 base_gtype
= g_ascii_strup(tmp
, -1);
748 gtk_entry_set_text(GTK_ENTRY(cc_dlg
->base_gtype_entry
), base_gtype
);
754 g_free(base_name_splitted
);
759 static gboolean
create_class(CreateClassDialog
*cc_dlg
)
761 ClassInfo
*class_info
;
766 g_return_val_if_fail(cc_dlg
!= NULL
, FALSE
);
768 if (utils_str_equal(gtk_entry_get_text(GTK_ENTRY(cc_dlg
->class_name_entry
)), ""))
771 class_info
= g_new0(ClassInfo
, 1);
772 class_info
->type
= cc_dlg
->class_type
;
773 class_info
->class_name
= g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg
->class_name_entry
)));
774 tmp
= str_case_split(class_info
->class_name
, '_');
775 class_info
->class_name_up
= g_ascii_strup(tmp
, -1);
776 class_info
->class_name_low
= g_ascii_strdown(class_info
->class_name_up
, -1);
777 if (! utils_str_equal(gtk_entry_get_text(GTK_ENTRY(cc_dlg
->base_name_entry
)), ""))
779 class_info
->base_name
= g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg
->base_name_entry
)));
780 if (class_info
->type
!= GEANY_CLASS_TYPE_PHP
)
782 class_info
->base_include
= g_strdup_printf("\n#include %c%s%c\n",
783 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg
->base_header_global_box
)) ?
785 gtk_entry_get_text(GTK_ENTRY(cc_dlg
->base_header_entry
)),
786 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg
->base_header_global_box
)) ?
791 class_info
->base_include
= g_strdup_printf("\nrequire_once \"%s\";\n",
792 gtk_entry_get_text(GTK_ENTRY(cc_dlg
->base_header_entry
)));
793 class_info
->base_decl
= g_strdup_printf(" extends %s", class_info
->base_name
);
798 class_info
->base_name
= g_strdup("");
799 class_info
->base_include
= g_strdup("");
801 if (cc_dlg
->header_entry
!= NULL
)
803 class_info
->header
= g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg
->header_entry
)));
804 class_info
->header_guard
= g_ascii_strup(class_info
->header
, -1);
805 g_strdelimit(class_info
->header_guard
, ".-", '_');
807 switch (class_info
->type
)
809 case GEANY_CLASS_TYPE_CPP
:
811 class_info
->source
= g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg
->source_entry
)));
812 if (! utils_str_equal(class_info
->base_name
, ""))
813 class_info
->base_decl
= g_strdup_printf(": public %s", class_info
->base_name
);
815 class_info
->base_decl
= g_strdup("");
816 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg
->create_constructor_box
)))
818 gchar
*base_constructor
;
820 if (utils_str_equal(class_info
->base_name
, ""))
821 base_constructor
= g_strdup("");
823 base_constructor
= g_strdup_printf("\t: %s()\n", class_info
->base_name
);
824 class_info
->constructor_decl
= g_strdup_printf("%s();\n", class_info
->class_name
);
825 class_info
->constructor_impl
= g_strdup_printf("\n%s::%s()\n%s{\n\t\n}\n",
826 class_info
->class_name
, class_info
->class_name
, base_constructor
);
827 g_free(base_constructor
);
831 class_info
->constructor_decl
= g_strdup("");
832 class_info
->constructor_impl
= g_strdup("");
834 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg
->create_destructor_box
)))
836 class_info
->destructor_decl
=
837 g_strdup_printf("virtual ~%s();\n", class_info
->class_name
);
838 class_info
->destructor_impl
= g_strdup_printf("\n%s::~%s()\n{\n\t\n}\n",
839 class_info
->class_name
, class_info
->class_name
);
843 class_info
->destructor_decl
= g_strdup("");
844 class_info
->destructor_impl
= g_strdup("");
848 case GEANY_CLASS_TYPE_GTK
:
850 class_info
->namespace = g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg
->class_namespace_entry
)));
851 if (EMPTY(class_info
->namespace))
853 class_info
->namespace_up
= g_strdup("");
854 class_info
->namespace_low
= g_strdup("");
858 gchar
*tmp_namespace
;
859 gchar
*tmp_namespace_split
;
861 tmp_namespace_split
= str_case_split(class_info
->namespace, '_');
862 tmp_namespace
= g_strconcat(tmp_namespace_split
, "_", NULL
);
863 class_info
->namespace_up
= g_ascii_strup(tmp_namespace
, -1);
864 class_info
->namespace_low
= g_ascii_strdown(class_info
->namespace_up
, -1);
865 g_free(tmp_namespace
);
866 g_free(tmp_namespace_split
);
868 class_info
->base_gtype
= g_strdup(gtk_entry_get_text(
869 GTK_ENTRY(cc_dlg
->base_gtype_entry
)));
870 class_info
->source
= g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg
->source_entry
)));
871 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg
->create_constructor_box
)))
873 class_info
->constructor_decl
= g_strdup_printf("%s *%s%s_new (void);\n",
874 gtk_entry_get_text(GTK_ENTRY(cc_dlg
->gtk_constructor_type_entry
)),
875 class_info
->namespace_low
, class_info
->class_name_low
);
876 class_info
->constructor_impl
= g_strdup_printf("\n"
880 " return g_object_new (%sTYPE_%s, NULL);\n"
882 gtk_entry_get_text(GTK_ENTRY(cc_dlg
->gtk_constructor_type_entry
)),
883 class_info
->namespace_low
, class_info
->class_name_low
,
884 class_info
->namespace_up
, class_info
->class_name_up
);
888 class_info
->constructor_decl
= g_strdup("");
889 class_info
->constructor_impl
= g_strdup("");
891 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg
->create_destructor_box
)))
893 class_info
->gtk_destructor_registration
=
894 g_strdup_printf("GObjectClass *g_object_class;\n\n"
895 " g_object_class = G_OBJECT_CLASS (klass);\n\n"
896 " g_object_class->finalize = %s%s_finalize;\n",
897 class_info
->namespace_low
, class_info
->class_name_low
);
898 class_info
->destructor_decl
=
899 g_strdup_printf("static void %s%s_finalize (GObject *object);\n",
900 class_info
->namespace_low
, class_info
->class_name_low
);
901 class_info
->destructor_impl
= g_strdup_printf("\n"
903 "%s%s_finalize (GObject *object)\n"
906 " g_return_if_fail (%sIS_%s (object));\n\n"
907 " self = %s%s (object);\n\n"
908 " G_OBJECT_CLASS (%s%s_parent_class)->finalize (object);\n"
910 class_info
->namespace_low
, class_info
->class_name_low
,
911 class_info
->namespace, class_info
->class_name
,
912 class_info
->namespace_up
, class_info
->class_name_up
,
913 class_info
->namespace_up
, class_info
->class_name_up
,
914 class_info
->namespace_low
, class_info
->class_name_low
);
918 class_info
->gtk_destructor_registration
= g_strdup("");
919 class_info
->destructor_decl
= g_strdup("");
920 class_info
->destructor_impl
= g_strdup("");
924 case GEANY_CLASS_TYPE_PHP
:
926 const gchar
*tmp_str
;
928 class_info
->source
= g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg
->source_entry
)));
930 tmp_str
= gtk_entry_get_text(GTK_ENTRY(cc_dlg
->class_namespace_entry
));
931 if (! utils_str_equal(tmp_str
, ""))
932 class_info
->namespace_decl
= g_strdup_printf("namespace %s;", tmp_str
);
934 class_info
->namespace_decl
= g_strdup("");
936 tmp_str
= gtk_entry_get_text(GTK_ENTRY(cc_dlg
->class_implements_entry
));
937 if (! utils_str_equal(tmp_str
, ""))
938 class_info
->implements_decl
= g_strdup_printf(" implements %s", tmp_str
);
940 class_info
->implements_decl
= g_strdup("");
942 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg
->create_constructor_box
)) &&
943 ! gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg
->create_isabstract_box
)))
945 class_info
->constructor_impl
= g_strdup_printf("\n"
947 "\t * Constructor of class %s.\n"
949 "\t * @return void\n"
951 "\tpublic function __construct()\n"
955 class_info
->class_name
);
957 else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg
->create_constructor_box
)) &&
958 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg
->create_isabstract_box
)))
960 class_info
->constructor_impl
= g_strdup_printf("\n"
962 "\t * Constructor of class %s.\n"
964 "\t * @return void\n"
966 "\tprotected function __construct()\n"
970 class_info
->class_name
);
973 class_info
->constructor_impl
= g_strdup("");
975 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg
->create_destructor_box
)))
977 class_info
->destructor_impl
= g_strdup_printf("\n"
979 "\t * Destructor of class %s.\n"
981 "\t * @return void\n"
983 "\tpublic function __destruct()\n"
987 class_info
->class_name
);
990 class_info
->destructor_impl
= g_strdup("");
992 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg
->create_isabstract_box
)))
993 class_info
->abstract_decl
= g_strdup("abstract ");
995 class_info
->abstract_decl
= g_strdup("");
997 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg
->create_issingleton_box
)))
999 class_info
->singleton_impl
= g_strdup_printf("\n"
1001 "\t * Holds instance of self.\n"
1005 "\tprotected static $kInstance = null;\n\n"
1007 "\t * Returns instance of self.\n"
1011 "\tpublic static function getInstance() {\n"
1012 "\t\tif(!(self::$kInstance instanceof %s)) {\n"
1013 "\t\t\tself::$kInstance = new self();\n"
1015 "\t\treturn self::$kInstance;\n"
1017 class_info
->class_name
,
1018 class_info
->class_name
,
1019 class_info
->class_name
);
1022 class_info
->singleton_impl
= g_strdup("");
1027 /* only create the files if the filename is not empty */
1028 if (! utils_str_equal(class_info
->source
, ""))
1030 doc
= document_new_file(class_info
->source
, NULL
, NULL
);
1031 text
= get_template_class_source(class_info
);
1032 editor_insert_text_block(doc
->editor
, text
, 0, -1, 0, TRUE
);
1034 sci_set_current_position(doc
->editor
->sci
, 0, TRUE
);
1037 if (! utils_str_equal(class_info
->header
, "") && class_info
->type
!= GEANY_CLASS_TYPE_PHP
)
1039 doc
= document_new_file(class_info
->header
, NULL
, NULL
);
1040 text
= get_template_class_header(class_info
);
1041 editor_insert_text_block(doc
->editor
, text
, 0, -1, 0, TRUE
);
1043 sci_set_current_position(doc
->editor
->sci
, 0, TRUE
);
1046 free_pointers(24, tmp
, class_info
->namespace, class_info
->namespace_up
,
1047 class_info
->namespace_low
, class_info
->class_name
, class_info
->class_name_up
,
1048 class_info
->base_name
, class_info
->class_name_low
, class_info
->base_include
,
1049 class_info
->header
, class_info
->header_guard
, class_info
->source
, class_info
->base_decl
,
1050 class_info
->constructor_decl
, class_info
->constructor_impl
,
1051 class_info
->gtk_destructor_registration
, class_info
->destructor_decl
,
1052 class_info
->destructor_impl
, class_info
->base_gtype
,
1053 class_info
->namespace_decl
, class_info
->implements_decl
,
1054 class_info
->abstract_decl
, class_info
->singleton_impl
, class_info
, NULL
);
1060 on_menu_create_cpp_class_activate (GtkMenuItem
*menuitem
,
1063 show_dialog_create_class(GEANY_CLASS_TYPE_CPP
);
1068 on_menu_create_gtk_class_activate (GtkMenuItem
*menuitem
,
1071 show_dialog_create_class(GEANY_CLASS_TYPE_GTK
);
1076 on_menu_create_php_class_activate (GtkMenuItem
*menuitem
,
1079 show_dialog_create_class(GEANY_CLASS_TYPE_PHP
);
1083 void plugin_init(GeanyData
*data
)
1085 GtkWidget
*menu_create_class1
;
1086 GtkWidget
*menu_create_class1_menu
;
1087 GtkWidget
*menu_create_cpp_class
;
1088 GtkWidget
*menu_create_gtk_class
;
1089 GtkWidget
*menu_create_php_class
;
1091 menu_create_class1
= ui_image_menu_item_new (GTK_STOCK_ADD
, _("Create Cla_ss"));
1092 gtk_container_add (GTK_CONTAINER (geany
->main_widgets
->tools_menu
), menu_create_class1
);
1094 menu_create_class1_menu
= gtk_menu_new ();
1095 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_create_class1
), menu_create_class1_menu
);
1097 menu_create_cpp_class
= gtk_menu_item_new_with_mnemonic (_("_C++ Class..."));
1098 gtk_container_add (GTK_CONTAINER (menu_create_class1_menu
), menu_create_cpp_class
);
1100 menu_create_gtk_class
= gtk_menu_item_new_with_mnemonic (_("_GTK+ Class..."));
1101 gtk_container_add (GTK_CONTAINER (menu_create_class1_menu
), menu_create_gtk_class
);
1103 menu_create_php_class
= gtk_menu_item_new_with_mnemonic (_("_PHP Class..."));
1104 gtk_container_add (GTK_CONTAINER (menu_create_class1_menu
), menu_create_php_class
);
1106 g_signal_connect(menu_create_cpp_class
, "activate",
1107 G_CALLBACK (on_menu_create_cpp_class_activate
),
1109 g_signal_connect(menu_create_gtk_class
, "activate",
1110 G_CALLBACK (on_menu_create_gtk_class_activate
),
1112 g_signal_connect(menu_create_php_class
, "activate",
1113 G_CALLBACK (on_menu_create_php_class_activate
),
1116 gtk_widget_show_all(menu_create_class1
);
1118 main_menu_item
= menu_create_class1
;
1122 void plugin_cleanup(void)
1124 gtk_widget_destroy(main_menu_item
);