geany/plugins/classbuilder.c
Enrico Tröger 2b07283739 Add plugin manager dialog to select plugins to load at startup and to call a plugin configure dialog.
Add configure symbol for plugins which is called by Geany when a configure dialog for the plugin is requested, optionally.
Add author field to plugin info struct.
Add sample configure dialog to the demo plugin.
Fix cleanup code in filebrowser plugin to remove it completely when unloaded.			


git-svn-id: https://geany.svn.sourceforge.net/svnroot/geany/trunk@2060 ea778897-0a13-0410-b9d1-a72fbfd435f5
2007-11-20 18:15:46 +00:00

817 lines
26 KiB
C

/*
* classbuilder.c - this file is part of Geany, a fast and lightweight IDE
*
* Copyright 2007 Alexander Rodin <rodin(dot)alexander(at)gmail(dot)com>
* Copyright 2007 Enrico Tröger <enrico.troeger@uvena.de>
* Copyright 2007 Nick Treleaven <nick.treleaven@btinternet.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
* $Id$
*/
/* Class Builder - creates source files containing a new class interface and definition. */
#include "geany.h"
#include "plugindata.h"
#include "support.h"
#include "filetypes.h"
#include "document.h"
PluginFields *plugin_fields;
GeanyData *geany_data;
#define doc_array geany_data->doc_array
// can't use document as a macro because it's currently a typename
#define documents geany_data->document
#define scintilla geany_data->sci
#define templates geany_data->templates
#define utils geany_data->utils
#define ui geany_data->ui
VERSION_CHECK(7)
PLUGIN_INFO(_("Class Builder"), _("Creates source files for new class types."), VERSION,
_("The Geany developer team"))
enum
{
GEANY_CLASS_TYPE_CPP,
GEANY_CLASS_TYPE_GTK
};
typedef struct _ClassInfo ClassInfo;
struct _ClassInfo
{
gint type;
gchar *class_name;
gchar *class_name_up;
gchar *class_name_low;
gchar *base_name;
gchar *base_gtype;
gchar *header;
gchar *header_guard;
gchar *base_include;
gchar *base_decl;
gchar *constructor_decl;
gchar *destructor_decl;
gchar *source;
gchar *constructor_impl;
gchar *destructor_impl;
gchar *gtk_destructor_registration;
};
typedef struct _CreateClassDialog
{
gint class_type;
GtkWidget *dialog;
GtkWidget *class_name_entry;
GtkWidget *header_entry;
GtkWidget *source_entry;
GtkWidget *base_name_entry;
GtkWidget *base_header_entry;
GtkWidget *base_header_global_box;
GtkWidget *base_gtype_entry;
GtkWidget *create_constructor_box;
GtkWidget *create_destructor_box;
GtkWidget *gtk_constructor_type_entry;
} CreateClassDialog;
static const gchar templates_cpp_class_header[] = "{fileheader}\n\n\
#ifndef {header_guard}\n\
#define {header_guard}\n\
{base_include}\n\
class {class_name}{base_decl}\n\
{\n\
public:\n\
{constructor_decl}\
{destructor_decl}\
\n\
private:\n\
// add your private declarations\n\
};\n\
\n\
#endif // {header_guard}\n\
";
static const gchar templates_cpp_class_source[] = "{fileheader}\n\n\
#include \"{header}\"\n\
\n\
{constructor_impl}\n\
{destructor_impl}\n\
";
static const gchar templates_gtk_class_header[] = "{fileheader}\n\n\
#ifndef __{header_guard}__\n\
#define __{header_guard}__\n\
{base_include}\n\
G_BEGIN_DECLS\n\
\n\
#define {class_name_up}_TYPE ({class_name_low}_get_type())\n\
#define {class_name_up}(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\\\n\
{class_name_up}_TYPE, {class_name}))\n\
#define {class_name_up}_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),\\\n\
{class_name_up}_TYPE, {class_name}Class))\n\
#define IS_{class_name_up}(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),\\\n\
{class_name_up}_TYPE))\n\
#define IS_{class_name_up}_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),\\\n\
{class_name_up}_TYPE))\n\
\n\
typedef struct _{class_name} {class_name};\n\
typedef struct _{class_name}Class {class_name}Class;\n\
\n\
struct _{class_name}\n\
{\n\
{base_name} parent;\n\
/* add your public declarations here */\n\
};\n\
\n\
struct _{class_name}Class\n\
{\n\
{base_name}Class parent_class;\n\
};\n\
\n\
GType {class_name_low}_get_type (void);\n\
{constructor_decl}\
\n\
G_END_DECLS\n\
\n\
#endif /* __{header_guard}__ */\n\
";
static const gchar templates_gtk_class_source[] = "{fileheader}\n\
#include \"{header}\"\n\
\n\
typedef struct _{class_name}Private {class_name}Private;\n\
\n\
#define {class_name_up}_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj),\\\n\
{class_name_up}_TYPE, {class_name}Private))\n\
\n\
struct _{class_name}Private\n\
{\n\
/* add your private declarations here */\n\
};\n\
\n\
static void {class_name_low}_class_init ({class_name}Class *klass);\n\
static void {class_name_low}_init ({class_name} *self);\n\
{destructor_decl}\
\n\
/* Local data */\n\
static {base_name}Class *parent_class = NULL;\n\
\n\
GType {class_name_low}_get_type(void)\n\
{\n\
static GType self_type = 0;\n\
if (! self_type)\n\
{\n\
static const GTypeInfo self_info = \n\
{\n\
sizeof({class_name}Class),\n\
NULL, /* base_init */\n\
NULL, /* base_finalize */\n\
(GClassInitFunc){class_name_low}_class_init,\n\
NULL, /* class_finalize */\n\
NULL, /* class_data */\n\
sizeof({class_name}),\n\
0,\n\
(GInstanceInitFunc){class_name_low}_init,\n\
NULL /* value_table */\n\
};\n\
\n\
self_type = g_type_register_static({base_gtype}, \"{class_name}\", &self_info, 0);\
}\n\
\n\
return self_type;\n\
}\n\
\n\
static void {class_name_low}_class_init({class_name}Class *klass)\n\
{\n\
{gtk_destructor_registration}\n\
parent_class = ({base_name}Class*)g_type_class_peek({base_gtype});\n\
g_type_class_add_private((gpointer)klass, sizeof({class_name}Private));\n\
}\n\
\n\
static void {class_name_low}_init({class_name} *self)\n\
{\n\
\n\
}\n\
\n\
{constructor_impl}\n\
{destructor_impl}\n\
";
static void cc_dlg_on_set_sensitive_toggled(GtkWidget *toggle_button, GtkWidget *target_widget);
static void cc_dlg_on_class_name_entry_changed(GtkWidget *entry, CreateClassDialog *cc_dlg);
static void cc_dlg_on_base_name_entry_changed(GtkWidget *entry, CreateClassDialog *cc_dlg);
static void cc_dlg_on_create_class(CreateClassDialog *cc_dlg);
/* I don't want this to be in the plugin API because it can cause leaks if any pointers
* are NULL -ntrel. */
/* Frees all passed pointers if they are *ALL* non-NULL.
* Do not use if any pointers may be NULL.
* The first argument is nothing special, it will also be freed.
* The list must be ended with NULL. */
static void
utils_free_pointers(gpointer first, ...)
{
va_list a;
gpointer sa;
for (va_start(a, first); (sa = va_arg(a, gpointer), sa!=NULL);)
{
if (sa != NULL)
g_free(sa);
}
va_end(a);
if (first != NULL)
g_free(first);
}
static gchar*
get_template_class_header(ClassInfo *class_info)
{
gchar *fileheader = NULL;
GString *template = NULL;
switch (class_info->type)
{
case GEANY_CLASS_TYPE_CPP:
fileheader = templates->get_template_fileheader(GEANY_FILETYPES_CPP, class_info->header);
template = g_string_new(templates_cpp_class_header);
utils->string_replace_all(template, "{fileheader}", fileheader);
utils->string_replace_all(template, "{header_guard}", class_info->header_guard);
utils->string_replace_all(template, "{base_include}", class_info->base_include);
utils->string_replace_all(template, "{class_name}", class_info->class_name);
utils->string_replace_all(template, "{base_decl}", class_info->base_decl);
utils->string_replace_all(template, "{constructor_decl}",
class_info->constructor_decl);
utils->string_replace_all(template, "{destructor_decl}",
class_info->destructor_decl);
break;
case GEANY_CLASS_TYPE_GTK:
fileheader = templates->get_template_fileheader(GEANY_FILETYPES_C, class_info->header);
template = g_string_new(templates_gtk_class_header);
utils->string_replace_all(template, "{fileheader}", fileheader);
utils->string_replace_all(template, "{header_guard}", class_info->header_guard);
utils->string_replace_all(template, "{base_include}", class_info->base_include);
utils->string_replace_all(template, "{class_name}", class_info->class_name);
utils->string_replace_all(template, "{class_name_up}", class_info->class_name_up);
utils->string_replace_all(template, "{class_name_low}", class_info->class_name_low);
utils->string_replace_all(template, "{base_name}", class_info->base_name);
utils->string_replace_all(template, "{constructor_decl}",
class_info->constructor_decl);
break;
}
g_free(fileheader);
if (template)
return g_string_free(template, FALSE);
else
return NULL;
}
static gchar*
get_template_class_source(ClassInfo *class_info)
{
gchar *fileheader = NULL;
GString *template = NULL;
switch (class_info->type)
{
case GEANY_CLASS_TYPE_CPP:
fileheader = templates->get_template_fileheader(GEANY_FILETYPES_CPP, class_info->source);
template = g_string_new(templates_cpp_class_source);
utils->string_replace_all(template, "{fileheader}", fileheader);
utils->string_replace_all(template, "{header}", class_info->header);
utils->string_replace_all(template, "{class_name}", class_info->class_name);
utils->string_replace_all(template, "{base_include}", class_info->base_include);
utils->string_replace_all(template, "{base_name}", class_info->base_name);
utils->string_replace_all(template, "{constructor_impl}",
class_info->constructor_impl);
utils->string_replace_all(template, "{destructor_impl}",
class_info->destructor_impl);
break;
case GEANY_CLASS_TYPE_GTK:
fileheader = templates->get_template_fileheader(GEANY_FILETYPES_C, class_info->source);
template = g_string_new(templates_gtk_class_source);
utils->string_replace_all(template, "{fileheader}", fileheader);
utils->string_replace_all(template, "{header}", class_info->header);
utils->string_replace_all(template, "{class_name}", class_info->class_name);
utils->string_replace_all(template, "{class_name_up}", class_info->class_name_up);
utils->string_replace_all(template, "{class_name_low}", class_info->class_name_low);
utils->string_replace_all(template, "{base_name}", class_info->base_name);
utils->string_replace_all(template, "{base_gtype}", class_info->base_gtype);
utils->string_replace_all(template, "{destructor_decl}", class_info->destructor_decl);
utils->string_replace_all(template, "{constructor_impl}",
class_info->constructor_impl);
utils->string_replace_all(template, "{destructor_impl}",
class_info->destructor_impl);
utils->string_replace_all(template, "{gtk_destructor_registration}",
class_info->gtk_destructor_registration);
break;
}
g_free(fileheader);
if (template)
return g_string_free(template, FALSE);
else
return NULL;
}
void show_dialog_create_class(gint type)
{
CreateClassDialog *cc_dlg;
GtkWidget *main_box;
GtkWidget *frame;
GtkWidget *align;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *label;
cc_dlg = g_new0(CreateClassDialog, 1);
cc_dlg->class_type = type;
cc_dlg->dialog = gtk_dialog_new_with_buttons(_("Create Class"),
GTK_WINDOW(geany_data->app->window),
GTK_DIALOG_MODAL,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OK, GTK_RESPONSE_OK,
NULL);
g_signal_connect_swapped(G_OBJECT(cc_dlg->dialog), "destroy",
G_CALLBACK(g_free), (gpointer)cc_dlg);
main_box = ui->dialog_vbox_new(GTK_DIALOG(cc_dlg->dialog));
frame = ui->frame_new_with_alignment(_("Class"), &align);
gtk_container_add(GTK_CONTAINER(main_box), frame);
vbox = gtk_vbox_new(FALSE, 10);
gtk_container_add(GTK_CONTAINER(align), vbox);
hbox = gtk_hbox_new(FALSE, 10);
gtk_container_add(GTK_CONTAINER(vbox), hbox);
label = gtk_label_new(_("Class name:"));
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
cc_dlg->class_name_entry = gtk_entry_new();
gtk_box_pack_start(GTK_BOX(hbox), cc_dlg->class_name_entry, TRUE, TRUE, 0);
g_signal_connect(G_OBJECT(cc_dlg->class_name_entry), "changed",
G_CALLBACK(cc_dlg_on_class_name_entry_changed), cc_dlg);
hbox = gtk_hbox_new(FALSE, 10);
gtk_container_add(GTK_CONTAINER(vbox), hbox);
label = gtk_label_new(_("Header file:"));
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
cc_dlg->header_entry = gtk_entry_new();
gtk_container_add(GTK_CONTAINER(hbox), cc_dlg->header_entry);
hbox = gtk_hbox_new(FALSE, 10);
gtk_container_add(GTK_CONTAINER(vbox), hbox);
label = gtk_label_new(_("Source file:"));
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
cc_dlg->source_entry = gtk_entry_new();
gtk_container_add(GTK_CONTAINER(hbox), cc_dlg->source_entry);
frame = ui->frame_new_with_alignment(_("Inheritance"), &align);
gtk_container_add(GTK_CONTAINER(main_box), frame);
vbox = gtk_vbox_new(FALSE, 10);
gtk_container_add(GTK_CONTAINER(align), vbox);
hbox = gtk_hbox_new(FALSE, 10);
gtk_container_add(GTK_CONTAINER(vbox), hbox);
label = gtk_label_new(_("Base class:"));
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
cc_dlg->base_name_entry = gtk_entry_new();
if (type == GEANY_CLASS_TYPE_GTK)
gtk_entry_set_text(GTK_ENTRY(cc_dlg->base_name_entry), "GObject");
gtk_container_add(GTK_CONTAINER(hbox), cc_dlg->base_name_entry);
g_signal_connect(G_OBJECT(cc_dlg->base_name_entry), "changed",
G_CALLBACK(cc_dlg_on_base_name_entry_changed), (gpointer)cc_dlg);
hbox = gtk_hbox_new(FALSE, 10);
gtk_container_add(GTK_CONTAINER(vbox), hbox);
label = gtk_label_new(_("Base header:"));
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
cc_dlg->base_header_entry = gtk_entry_new();
if (type == GEANY_CLASS_TYPE_GTK)
gtk_entry_set_text(GTK_ENTRY(cc_dlg->base_header_entry), "glib-object.h");
gtk_container_add(GTK_CONTAINER(hbox), cc_dlg->base_header_entry);
cc_dlg->base_header_global_box = gtk_check_button_new_with_label(_("Global"));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cc_dlg->base_header_global_box), TRUE);
gtk_box_pack_end(GTK_BOX(hbox), cc_dlg->base_header_global_box, FALSE, FALSE, 0);
if (type == GEANY_CLASS_TYPE_GTK)
{
hbox = gtk_hbox_new(FALSE, 10);
gtk_container_add(GTK_CONTAINER(vbox), hbox);
label = gtk_label_new(_("Base GType:"));
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
cc_dlg->base_gtype_entry = gtk_entry_new();
gtk_entry_set_text(GTK_ENTRY(cc_dlg->base_gtype_entry), "GTK_TYPE_OBJECT");
gtk_container_add(GTK_CONTAINER(hbox), cc_dlg->base_gtype_entry);
}
frame = ui->frame_new_with_alignment(_("Options"), &align);
gtk_container_add(GTK_CONTAINER(main_box), frame);
vbox = gtk_vbox_new(FALSE, 10);
gtk_container_add(GTK_CONTAINER(align), vbox);
hbox = gtk_hbox_new(FALSE, 10);
gtk_container_add(GTK_CONTAINER(vbox), hbox);
cc_dlg->create_constructor_box = gtk_check_button_new_with_label(_("Create constructor"));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cc_dlg->create_constructor_box), TRUE);
gtk_container_add(GTK_CONTAINER(hbox), cc_dlg->create_constructor_box);
cc_dlg->create_destructor_box = gtk_check_button_new_with_label(_("Create destructor"));
gtk_container_add(GTK_CONTAINER(hbox), cc_dlg->create_destructor_box);
if (type == GEANY_CLASS_TYPE_GTK)
{
hbox = gtk_hbox_new(FALSE, 10);
gtk_container_add(GTK_CONTAINER(vbox), hbox);
g_signal_connect(G_OBJECT(cc_dlg->create_constructor_box), "toggled",
G_CALLBACK(cc_dlg_on_set_sensitive_toggled), (gpointer)hbox);
label = gtk_label_new(_("GTK+ constructor type"));
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
cc_dlg->gtk_constructor_type_entry = gtk_entry_new();
gtk_entry_set_text(GTK_ENTRY(cc_dlg->gtk_constructor_type_entry), "GObject");
gtk_container_add(GTK_CONTAINER(hbox), cc_dlg->gtk_constructor_type_entry);
}
gtk_widget_show_all(cc_dlg->dialog);
if (gtk_dialog_run(GTK_DIALOG(cc_dlg->dialog)) == GTK_RESPONSE_OK)
cc_dlg_on_create_class(cc_dlg);
gtk_widget_destroy(cc_dlg->dialog);
// g_object_unref(G_OBJECT(cc_dlg->dialog));
}
static void cc_dlg_on_set_sensitive_toggled(GtkWidget *toggle_button, GtkWidget *target_widget)
{
g_return_if_fail(toggle_button != NULL);
g_return_if_fail(GTK_IS_TOGGLE_BUTTON(toggle_button));
g_return_if_fail(target_widget != NULL);
g_return_if_fail(GTK_IS_WIDGET(target_widget));
gtk_widget_set_sensitive(target_widget,
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle_button)));
}
static void cc_dlg_on_class_name_entry_changed(GtkWidget *entry, CreateClassDialog *cc_dlg)
{
gchar *class_name_down;
gchar *class_header;
gchar *class_source;
g_return_if_fail(entry != NULL);
g_return_if_fail(GTK_IS_ENTRY(entry));
g_return_if_fail(cc_dlg != NULL);
class_name_down = g_ascii_strdown(gtk_entry_get_text(GTK_ENTRY(entry)), -1);
class_header = g_strconcat(class_name_down, ".h", NULL);
if (cc_dlg->class_type == GEANY_CLASS_TYPE_CPP)
class_source = g_strconcat(class_name_down, ".cpp", NULL);
else
class_source = g_strconcat(class_name_down, ".c", NULL);
gtk_entry_set_text(GTK_ENTRY(cc_dlg->header_entry), class_header);
gtk_entry_set_text(GTK_ENTRY(cc_dlg->source_entry), class_source);
g_free(class_name_down);
g_free(class_header);
g_free(class_source);
}
static gchar* str_case_split(const gchar *str, gchar splitter)
{
GString *result;
g_return_val_if_fail(str != NULL, NULL);
if (*str == '\0')
return g_strdup("");
result = g_string_new(NULL);
g_string_append_c(result, *str);
while (*(++str) != '\0')
{
if (g_ascii_isupper(*str) && g_ascii_islower(result->str[result->len - 1]))
g_string_append_c(result, splitter);
g_string_append_c(result, *str);
}
return g_string_free(result, FALSE);
}
static void cc_dlg_on_base_name_entry_changed(GtkWidget *entry, CreateClassDialog *cc_dlg)
{
gchar *base_name_splitted;
gchar *base_header;
gchar *tmp;
g_return_if_fail(entry != NULL);
g_return_if_fail(GTK_IS_ENTRY(entry));
g_return_if_fail(cc_dlg != NULL);
base_name_splitted = str_case_split(gtk_entry_get_text(GTK_ENTRY(entry)), '_');
if (! g_ascii_strncasecmp(gtk_entry_get_text(GTK_ENTRY(entry)), "gtk", 3))
tmp = g_strconcat("gtk/", gtk_entry_get_text(GTK_ENTRY(entry)), ".h", NULL);
else if (utils->str_equal(gtk_entry_get_text(GTK_ENTRY(entry)), "GObject"))
tmp = g_strdup("glib-object.h");
else
tmp = g_strconcat(gtk_entry_get_text(GTK_ENTRY(entry)), ".h", NULL);
base_header = g_ascii_strdown(tmp, -1);
g_free(tmp);
gtk_entry_set_text(GTK_ENTRY(cc_dlg->base_header_entry), base_header);
if (cc_dlg->class_type == GEANY_CLASS_TYPE_GTK)
{
gchar *base_gtype;
if (! g_ascii_strncasecmp(gtk_entry_get_text(GTK_ENTRY(entry)), "gtk", 3))
tmp = g_strdup_printf("%.3s_TYPE%s",
base_name_splitted,
base_name_splitted + 3);
else if (utils->str_equal(gtk_entry_get_text(GTK_ENTRY(entry)), "GObject"))
tmp = g_strdup("G_TYPE_OBJECT");
else
tmp = g_strconcat(base_name_splitted, "_TYPE", NULL);
base_gtype = g_ascii_strup(tmp, -1);
gtk_entry_set_text(GTK_ENTRY(cc_dlg->base_gtype_entry), base_gtype);
g_free(base_gtype);
g_free(tmp);
}
g_free(base_name_splitted);
g_free(base_header);
}
static void cc_dlg_on_create_class(CreateClassDialog *cc_dlg)
{
ClassInfo *class_info;
gint idx;
gchar *text;
gchar *tmp;
g_return_if_fail(cc_dlg != NULL);
if (utils->str_equal(gtk_entry_get_text(GTK_ENTRY(cc_dlg->class_name_entry)), ""))
return;
class_info = g_new0(ClassInfo, 1);
class_info->type = cc_dlg->class_type;
class_info->class_name = g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg->class_name_entry)));
tmp = str_case_split(class_info->class_name, '_');
class_info->class_name_up = g_ascii_strup(tmp, -1);
class_info->class_name_low = g_ascii_strdown(class_info->class_name_up, -1);
if (! utils->str_equal(gtk_entry_get_text(GTK_ENTRY(cc_dlg->base_name_entry)), ""))
{
class_info->base_name = g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg->base_name_entry)));
class_info->base_include = g_strdup_printf("\n#include %c%s%c\n",
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->base_header_global_box)) ?
'<' : '\"',
gtk_entry_get_text(GTK_ENTRY(cc_dlg->base_header_entry)),
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->base_header_global_box)) ?
'>' : '\"');
}
else
{
class_info->base_name = g_strdup("");
class_info->base_include = g_strdup("");
}
class_info->header = g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg->header_entry)));
class_info->header_guard = g_ascii_strup(class_info->header, -1);
g_strdelimit(class_info->header_guard, ".", '_');
switch (class_info->type)
{
case GEANY_CLASS_TYPE_CPP:
{
class_info->source = g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg->source_entry)));
if (! utils->str_equal(class_info->base_name, ""))
class_info->base_decl = g_strdup_printf(": public %s", class_info->base_name);
else
class_info->base_decl = g_strdup("");
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_constructor_box)))
{
gchar *base_constructor;
if (utils->str_equal(class_info->base_name, ""))
base_constructor = g_strdup("");
else
base_constructor = g_strdup_printf("\t: %s()\n", class_info->base_name);
class_info->constructor_decl = g_strdup_printf("%s();\n", class_info->class_name);
class_info->constructor_impl = g_strdup_printf("\n%s::%s()\n%s{\n\t\n}\n",
class_info->class_name, class_info->class_name, base_constructor);
g_free(base_constructor);
}
else
{
class_info->constructor_decl = g_strdup("");
class_info->constructor_impl = g_strdup("");
}
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_destructor_box)))
{
class_info->destructor_decl =
g_strdup_printf("virtual ~%s();\n", class_info->class_name);
class_info->destructor_impl = g_strdup_printf("\n%s::~%s()\n{\n\t\n}\n",
class_info->class_name, class_info->class_name);
}
else
{
class_info->destructor_decl = g_strdup("");
class_info->destructor_impl = g_strdup("");
}
break;
}
case GEANY_CLASS_TYPE_GTK:
{
class_info->base_gtype = g_strdup(gtk_entry_get_text(
GTK_ENTRY(cc_dlg->base_gtype_entry)));
class_info->source = g_strdup(gtk_entry_get_text(GTK_ENTRY(cc_dlg->source_entry)));
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_constructor_box)))
{
class_info->constructor_decl = g_strdup_printf("%s*\t%s_new\t\t\t(void);\n",
gtk_entry_get_text(GTK_ENTRY(cc_dlg->gtk_constructor_type_entry)),
class_info->class_name_low);
class_info->constructor_impl = g_strdup_printf("\n"
"%s* %s_new(void)\n"
"{\n"
"\treturn (%s*)g_object_new(%s_TYPE, NULL);\n"
"}\n",
gtk_entry_get_text(GTK_ENTRY(cc_dlg->gtk_constructor_type_entry)),
class_info->class_name_low,
gtk_entry_get_text(GTK_ENTRY(cc_dlg->gtk_constructor_type_entry)),
class_info->class_name_up);
}
else
{
class_info->constructor_decl = g_strdup("");
class_info->constructor_impl = g_strdup("");
}
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc_dlg->create_destructor_box)))
{
class_info->gtk_destructor_registration =
g_strdup_printf("GObjectClass *g_object_class;\n\n"
"\tg_object_class = G_OBJECT_CLASS(klass);\n\n"
"\tg_object_class->finalize = %s_finalize;\n",
class_info->class_name_low);
class_info->destructor_decl =
g_strdup_printf("static void %s_finalize\t\t\t(GObject *object);\n",
class_info->class_name_low);
class_info->destructor_impl = g_strdup_printf("\n"
"void %s_finalize(GObject *object)\n"
"{\n"
"\t%s *self;\n\n"
"\tg_return_if_fail(object != NULL);\n"
"\tg_return_if_fail(IS_%s(object));\n\n"
"\tself = %s(object);\n\n"
"\tif (G_OBJECT_CLASS(parent_class)->finalize)\n"
"\t\t(* G_OBJECT_CLASS(parent_class)->finalize)(object);\n"
"}\n",
class_info->class_name_low,
class_info->class_name,
class_info->class_name_up,
class_info->class_name_up);
}
else
{
class_info->gtk_destructor_registration = g_strdup("");
class_info->destructor_decl = g_strdup("");
class_info->destructor_impl = g_strdup("");
}
break;
}
}
// only create the files if the filename is not empty
if (! utils->str_equal(class_info->source, ""))
{
text = get_template_class_source(class_info);
idx = documents->new_file(class_info->source, NULL, NULL);
scintilla->set_text(doc_list[idx].sci, text);
g_free(text);
}
if (! utils->str_equal(class_info->header, ""))
{
text = get_template_class_header(class_info);
idx = documents->new_file(class_info->header, NULL, NULL);
scintilla->set_text(doc_list[idx].sci, text);
g_free(text);
}
utils_free_pointers(tmp, class_info->class_name, class_info->class_name_up,
class_info->base_name, class_info->class_name_low, class_info->base_include,
class_info->header, class_info->header_guard, class_info->source, class_info->base_decl,
class_info->constructor_decl, class_info->constructor_impl,
class_info->gtk_destructor_registration, class_info->destructor_decl,
class_info->destructor_impl, class_info->base_gtype, class_info, NULL);
}
static void
on_menu_create_cpp_class_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
show_dialog_create_class(GEANY_CLASS_TYPE_CPP);
}
static void
on_menu_create_gtk_class_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
show_dialog_create_class(GEANY_CLASS_TYPE_GTK);
}
void init(GeanyData *data)
{
GtkWidget *menu_create_class1;
GtkWidget *image1861;
GtkWidget *menu_create_class1_menu;
GtkWidget *menu_create_cpp_class;
GtkWidget *menu_create_gtk_class;
menu_create_class1 = gtk_image_menu_item_new_with_mnemonic (_("Create Cla_ss"));
gtk_container_add (GTK_CONTAINER (data->tools_menu), menu_create_class1);
image1861 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_create_class1), image1861);
menu_create_class1_menu = gtk_menu_new ();
gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_create_class1), menu_create_class1_menu);
menu_create_cpp_class = gtk_menu_item_new_with_mnemonic (_("C++ Class"));
gtk_container_add (GTK_CONTAINER (menu_create_class1_menu), menu_create_cpp_class);
menu_create_gtk_class = gtk_menu_item_new_with_mnemonic (_("GTK+ Class"));
gtk_container_add (GTK_CONTAINER (menu_create_class1_menu), menu_create_gtk_class);
g_signal_connect ((gpointer) menu_create_cpp_class, "activate",
G_CALLBACK (on_menu_create_cpp_class_activate),
NULL);
g_signal_connect ((gpointer) menu_create_gtk_class, "activate",
G_CALLBACK (on_menu_create_gtk_class_activate),
NULL);
gtk_widget_show_all(menu_create_class1);
plugin_fields->menu_item = menu_create_class1;
}
void cleanup()
{
gtk_widget_destroy(plugin_fields->menu_item);
}