1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*  plugin.c
3  *  Copyright (C) 2005 Massimo Cora'
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU Library General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19 
20 #include <config.h>
21 #include <gtk/gtk.h>
22 #include <glib/gi18n.h>
23 #include <libanjuta/anjuta-preferences.h>
24 #include <libanjuta/anjuta-debug.h>
25 #include <libanjuta/anjuta-autogen.h>
26 #include <libanjuta/interfaces/ianjuta-wizard.h>
27 #include <libanjuta/interfaces/ianjuta-project-manager.h>
28 #include <libanjuta/interfaces/ianjuta-file-loader.h>
29 #include <libanjuta/interfaces/ianjuta-vcs.h>
30 #include <libanjuta/interfaces/ianjuta-editor.h>
31 #include <libanjuta/interfaces/ianjuta-document-manager.h>
32 
33 
34 #include "plugin.h"
35 /* #include "class_gen.h" */
36 
37 #include "window.h"
38 
39 #define ICON_FILE "anjuta-class-gen-plugin-48.png"
40 
41 /* Common editor preferences */
42 #define ANJUTA_PREF_SCHEMA_PREFIX "org.gnome.anjuta."
43 
44 /* Indentation template variables */
45 #define INDENT_WIDTH_PROPERTY "IndentWidth"
46 #define TAB_WIDTH_PROPERTY "TabWidth"
47 #define USE_TABS_PROPERTY "UseTabs"
48 
49 static gpointer parent_class;
50 
51 static void
project_root_added(AnjutaPlugin * plugin,G_GNUC_UNUSED const gchar * name,const GValue * value,G_GNUC_UNUSED gpointer user_data)52 project_root_added (AnjutaPlugin *plugin,
53                     G_GNUC_UNUSED const gchar *name,
54                     const GValue *value,
55 					G_GNUC_UNUSED gpointer user_data)
56 {
57 	AnjutaClassGenPlugin *cg_plugin;
58 	const gchar *root_uri;
59 
60 	cg_plugin = ANJUTA_PLUGIN_CLASS_GEN (plugin);
61 	root_uri = g_value_get_string (value);
62 
63 	if (root_uri)
64 	{
65 		gchar *root_dir = anjuta_util_get_local_path_from_uri (root_uri);
66 		if (root_dir)
67 			cg_plugin->top_dir = g_strdup(root_dir);
68 		else
69 			cg_plugin->top_dir = NULL;
70 		g_free (root_dir);
71 	}
72 	else
73 		cg_plugin->top_dir = NULL;
74 }
75 
76 static void
project_root_removed(AnjutaPlugin * plugin,G_GNUC_UNUSED const gchar * name,G_GNUC_UNUSED gpointer user_data)77 project_root_removed (AnjutaPlugin *plugin,
78                       G_GNUC_UNUSED const gchar *name,
79 					  G_GNUC_UNUSED gpointer user_data)
80 {
81 	AnjutaClassGenPlugin *cg_plugin;
82 	cg_plugin = ANJUTA_PLUGIN_CLASS_GEN (plugin);
83 
84 	if (cg_plugin->top_dir)
85 		g_free(cg_plugin->top_dir);
86 	cg_plugin->top_dir = NULL;
87 }
88 
89 static gboolean
activate_plugin(AnjutaPlugin * plugin)90 activate_plugin (AnjutaPlugin *plugin)
91 {
92 	AnjutaClassGenPlugin *cg_plugin;
93 
94 	DEBUG_PRINT ("%s", "AnjutaClassGenPlugin: Activating ClassGen plugin...");
95 	cg_plugin = ANJUTA_PLUGIN_CLASS_GEN (plugin);
96 	cg_plugin->prefs = anjuta_shell_get_preferences (plugin->shell, NULL);
97 
98 	g_return_val_if_fail (cg_plugin->prefs != NULL, FALSE);
99 
100 	cg_plugin->top_dir = NULL;
101 
102 	/* Check if autogen is present */
103 	if(!anjuta_check_autogen())
104 	{
105 		anjuta_util_dialog_error(
106 			NULL,
107 			_("Could not find autogen version 5; please install the "
108 			  "autogen package. You can get it from "
109 			  "http://autogen.sourceforge.net."));
110 
111 		return FALSE;
112 	}
113 
114 	/* set up project directory watch */
115 	cg_plugin->root_watch_id = anjuta_plugin_add_watch (plugin,
116 									IANJUTA_PROJECT_MANAGER_PROJECT_ROOT_URI,
117 									project_root_added,
118 									project_root_removed, NULL);
119 
120 	return TRUE;
121 }
122 
123 static gboolean
deactivate_plugin(AnjutaPlugin * plugin)124 deactivate_plugin (AnjutaPlugin *plugin)
125 {
126 	AnjutaClassGenPlugin *cg_plugin;
127 	cg_plugin = ANJUTA_PLUGIN_CLASS_GEN (plugin);
128 	DEBUG_PRINT ("%s", "AnjutaClassGenPlugin: Deactivating ClassGen plugin ...");
129 
130 	/* Remove watches */
131 	anjuta_plugin_remove_watch (plugin, cg_plugin->root_watch_id, TRUE);
132 
133 	return TRUE;
134 }
135 
136 static void
dispose(GObject * obj)137 dispose (GObject *obj)
138 {
139 	G_OBJECT_CLASS (parent_class)->dispose (obj);
140 }
141 
142 static void
finalize(GObject * obj)143 finalize (GObject *obj)
144 {
145 	AnjutaClassGenPlugin *cg_plugin;
146 	cg_plugin = ANJUTA_PLUGIN_CLASS_GEN (obj);
147 	g_free (cg_plugin->top_dir);
148 
149 	if(cg_plugin->window != NULL)
150 		g_object_unref(G_OBJECT(cg_plugin->window));
151 	if(cg_plugin->generator != NULL)
152 		g_object_unref(G_OBJECT(cg_plugin->generator));
153 
154 	G_OBJECT_CLASS (parent_class)->finalize (obj);
155 }
156 
157 static void
class_gen_plugin_class_init(GObjectClass * klass)158 class_gen_plugin_class_init (GObjectClass *klass)
159 {
160 	AnjutaPluginClass *plugin_class = ANJUTA_PLUGIN_CLASS (klass);
161 
162 	parent_class = g_type_class_peek_parent (klass);
163 
164 	plugin_class->activate = activate_plugin;
165 	plugin_class->deactivate = deactivate_plugin;
166 	klass->dispose = dispose;
167 	klass->finalize = finalize;
168 }
169 
170 static void
class_gen_plugin_instance_init(GObject * obj)171 class_gen_plugin_instance_init (GObject *obj)
172 {
173 	AnjutaClassGenPlugin *plugin = ANJUTA_PLUGIN_CLASS_GEN (obj);
174 	plugin->root_watch_id = 0;
175 	plugin->top_dir = NULL;
176 	plugin->window = NULL;
177 	plugin->generator = NULL;
178 }
179 
180 static gboolean
cg_plugin_add_to_project(AnjutaClassGenPlugin * plugin,const gchar * header_file,const gchar * source_file,gchar ** new_header_file,gchar ** new_source_file,GFile * target)181 cg_plugin_add_to_project (AnjutaClassGenPlugin *plugin,
182                           const gchar *header_file,
183                           const gchar *source_file,
184                           gchar **new_header_file,
185                           gchar **new_source_file,
186                           GFile *target)
187 {
188 	IAnjutaProjectManager *manager;
189 	GFile *header = NULL;
190 	GFile *source;
191 	gboolean result;
192 
193 	manager = anjuta_shell_get_interface (ANJUTA_PLUGIN (plugin)->shell,
194 	                                      IAnjutaProjectManager, NULL);
195 
196 	if (manager == NULL)
197 		return FALSE;
198 
199 	source = ianjuta_project_manager_add_source_quiet (manager, source_file,
200 	                                                   target, NULL);
201 	if (header_file) header = ianjuta_project_manager_add_source_quiet (manager, header_file,
202 	                                                                    target, NULL);
203 
204 	result = source != NULL;
205 	if (result)
206 	{
207 		*new_source_file = g_file_get_path(source);
208 		g_object_unref (source);
209 		*new_header_file = NULL;
210 		/*
211 		 * Check if we're dealing with a programming language not having header
212 		 * files.
213 		 */
214 		if (header_file != NULL)
215 		{
216 			if (header == NULL)
217 			{
218 				result = FALSE;
219 			}
220 			else
221 			{
222 				*new_header_file = g_file_get_path(header);
223 				g_object_unref (header);
224 			}
225 		}
226 	}
227 
228 	return result;
229 }
230 
231 static void
cg_plugin_add_to_repository(AnjutaClassGenPlugin * plugin,GFile * header_file,GFile * source_file)232 cg_plugin_add_to_repository (AnjutaClassGenPlugin *plugin,
233                              GFile *header_file,
234                              GFile *source_file)
235 {
236 	IAnjutaVcs *vcs;
237 	vcs = anjuta_shell_get_interface (ANJUTA_PLUGIN (plugin)->shell,
238 	                                  IAnjutaVcs, NULL);
239 
240 	if(vcs != NULL)
241 	{
242 		GList* files = NULL;
243 		AnjutaAsyncNotify* notify = anjuta_async_notify_new ();
244 		if (header_file != NULL) files = g_list_append (files, header_file);
245 		files = g_list_append (files, source_file);
246 		ianjuta_vcs_add (vcs, files, notify, NULL);
247 		g_list_free (files);
248 	}
249 }
250 
251 static void
cg_plugin_generator_error_cb(G_GNUC_UNUSED CgGenerator * generator,GError * error,gpointer user_data)252 cg_plugin_generator_error_cb (G_GNUC_UNUSED CgGenerator *generator,
253                               GError *error,
254                               gpointer user_data)
255 {
256 	AnjutaClassGenPlugin *plugin;
257 	plugin = (AnjutaClassGenPlugin *) user_data;
258 
259 	anjuta_util_dialog_error (
260 		GTK_WINDOW (cg_window_get_dialog (plugin->window)),
261 		_("Failed to execute autogen: %s"), error->message);
262 
263 	gtk_widget_set_sensitive (
264 		GTK_WIDGET (cg_window_get_dialog (plugin->window)), TRUE);
265 }
266 
267 static gboolean
cg_plugin_load(AnjutaClassGenPlugin * plugin,CgGenerator * generator,const gchar * file,GError ** error)268 cg_plugin_load (AnjutaClassGenPlugin *plugin,
269                 CgGenerator *generator,
270                 const gchar *file,
271                 GError **error)
272 {
273 	IAnjutaDocumentManager *docman;
274 	IAnjutaEditor *editor;
275 	gchar *name;
276 	gchar *contents;
277 	gboolean result;
278 
279 	docman = anjuta_shell_get_interface (ANJUTA_PLUGIN (plugin)->shell,
280 	                                     IAnjutaDocumentManager, NULL);
281 
282 	if(g_file_get_contents(file, &contents, NULL, error) == FALSE)
283 		return FALSE;
284 
285 	name = g_path_get_basename (file);
286 
287 	result = FALSE;
288 	/* The content argument seems not to work */
289 	editor = ianjuta_document_manager_add_buffer (docman, name, "", error);
290 
291 	if(editor != NULL)
292 	{
293 		ianjuta_editor_append(editor, contents, -1, error);
294 		if(!error || *error == NULL)
295 			result = TRUE;
296 	}
297 
298 	g_free(contents);
299 	g_free(name);
300 
301 	return result;
302 }
303 
304 static void
cg_plugin_generator_created_cb(CgGenerator * generator,gpointer user_data)305 cg_plugin_generator_created_cb (CgGenerator *generator,
306                                 gpointer user_data)
307 {
308 	AnjutaClassGenPlugin *plugin;
309 	const gchar *header_file;
310 	const gchar *source_file;
311 	IAnjutaFileLoader *loader;
312 
313 	plugin = (AnjutaClassGenPlugin *) user_data;
314 	header_file = cg_generator_get_header_destination (generator);
315 	source_file = cg_generator_get_source_destination (generator);
316 
317 	loader = anjuta_shell_get_interface (ANJUTA_PLUGIN (plugin)->shell,
318 	                                     IAnjutaFileLoader, NULL);
319 
320 	if (cg_window_get_add_to_project (plugin->window))
321 	{
322 		GFile* header = NULL;
323 		GFile* source = g_file_new_for_path (source_file);
324 		IAnjutaProjectManager *manager;
325         /*
326          * Check if we're workign with a programming language that
327          * doesn't need header files.  If yes, don't create two tabs,
328          * as the header and source will be the same file.
329          */
330 		if (header_file == NULL)
331 		{
332 			ianjuta_file_loader_load (loader, source, FALSE, NULL);
333 		}
334 		else
335 		{
336 			header = g_file_new_for_path (header_file);
337 			ianjuta_file_loader_load (loader, header, FALSE, NULL);
338 			ianjuta_file_loader_load (loader, source, FALSE, NULL);
339 		}
340 
341 		if (cg_window_get_add_to_repository (plugin->window))
342 		{
343 			cg_plugin_add_to_repository (plugin, header, source);
344 		}
345 
346 		manager = anjuta_shell_get_interface (ANJUTA_PLUGIN (plugin)->shell, IAnjutaProjectManager, NULL);
347 		if (manager)
348 		{
349 			if (header == NULL)
350 			{
351 			    g_signal_emit_by_name (G_OBJECT (manager), "element_added", source);
352 			}
353 			else
354 			{
355 			    g_signal_emit_by_name (G_OBJECT (manager), "element_added", header);
356 			    g_signal_emit_by_name (G_OBJECT (manager), "element_added", source);
357 			}
358 
359 		}
360 
361 		if (header != NULL) g_object_unref (header);
362 		g_object_unref (source);
363 	}
364 	else
365 	{
366 		if (header_file == NULL)
367 		{
368 			/* We do not just use ianjuta_file_leader_load here to ensure that
369 			 * the new documents are flagged as changed and no path is
370 			 * already set. */
371 			cg_plugin_load (plugin, generator, source_file, NULL);
372 		}
373 		else
374 		{
375 			cg_plugin_load (plugin, generator, header_file, NULL);
376 			cg_plugin_load (plugin, generator, source_file, NULL);
377 		}
378 	}
379 
380 	g_object_unref (G_OBJECT (plugin->window));
381 	plugin->window = NULL;
382 }
383 
384 static void
cg_plugin_window_response_cb(G_GNUC_UNUSED GtkDialog * dialog,gint response_id,gpointer user_data)385 cg_plugin_window_response_cb (G_GNUC_UNUSED GtkDialog *dialog,
386                               gint response_id,
387                               gpointer user_data)
388 {
389 	AnjutaClassGenPlugin *plugin;
390 	IAnjutaProjectManager *manager;
391 	GHashTable *values;
392 	GError *error;
393 	gchar *name;
394 
395 	gchar *header_file;
396 	gchar *source_file;
397 	gboolean result;
398 
399 	plugin = (AnjutaClassGenPlugin *) user_data;
400 	error = NULL;
401 
402 	if (response_id == GTK_RESPONSE_ACCEPT)
403 	{
404 		if (cg_window_get_add_to_project (plugin->window))
405 		{
406 			GFile *target = cg_window_get_selected_target (plugin->window);
407 			result = cg_plugin_add_to_project (
408 				plugin, cg_window_get_header_file (plugin->window),
409 					cg_window_get_source_file (plugin->window),
410 					&header_file, &source_file,
411 			        target);
412 		}
413 		else
414 		{
415 			header_file = cg_window_get_header_file (plugin->window) != NULL ? g_build_filename (g_get_tmp_dir (),
416 				cg_window_get_header_file (plugin->window), NULL) : NULL;
417 			source_file = g_build_filename (g_get_tmp_dir (),
418 				cg_window_get_source_file (plugin->window), NULL);
419 
420 			result = TRUE;
421 		}
422 
423 		if (result == TRUE)
424 		{
425 			GSettings *settings;
426 			gboolean flag;
427 			gint i;
428 
429 			values = cg_window_create_value_heap (plugin->window);
430 
431 			manager = anjuta_shell_get_interface (ANJUTA_PLUGIN (plugin)->shell,
432 			                                      IAnjutaProjectManager, NULL);
433 
434 			if (manager != NULL && plugin->top_dir != NULL)
435 			{
436 				/* Use basename of the project's root URI as project name. */
437 				name = g_path_get_basename (plugin->top_dir);
438 				g_hash_table_insert (values, "ProjectName", name);
439 			}
440 			else
441 			{
442 				name = g_path_get_basename (cg_window_get_source_file(
443 				                            plugin->window));
444 				g_hash_table_insert (values, "ProjectName", name);
445 			}
446 
447 			/* Set indentation settings */
448 			/* Add use-tabs property */
449 			settings = g_settings_new (ANJUTA_PREF_SCHEMA_PREFIX IANJUTA_EDITOR_PREF_SCHEMA);
450 			flag = g_settings_get_boolean (settings, IANJUTA_EDITOR_USE_TABS_KEY);
451 			g_hash_table_insert (values, USE_TABS_PROPERTY, g_strdup (flag ? "1" : "0"));
452 
453 			/* Add tab-width property */
454 			i = g_settings_get_int (settings, IANJUTA_EDITOR_TAB_WIDTH_KEY);
455 			g_hash_table_insert (values, TAB_WIDTH_PROPERTY, g_strdup_printf("%d", i));
456 
457 			/* Add indent-width property */
458 			i = g_settings_get_int (settings, IANJUTA_EDITOR_INDENT_WIDTH_KEY);
459 			g_hash_table_insert (values, INDENT_WIDTH_PROPERTY, g_strdup_printf("%d", i));
460 			g_object_unref (settings);
461 
462     		plugin->generator = cg_generator_new (
463 				cg_window_get_header_template(plugin->window),
464 				cg_window_get_source_template(plugin->window),
465 				header_file,
466 				source_file);
467 
468 			if (cg_generator_run (plugin->generator, values, &error) == FALSE)
469 			{
470 				anjuta_util_dialog_error (
471 					GTK_WINDOW (cg_window_get_dialog (plugin->window)),
472 					_("Failed to execute autogen: %s"), error->message);
473 
474 				g_object_unref (G_OBJECT (plugin->generator));
475 				g_error_free (error);
476 			}
477 			else
478 			{
479 				g_signal_connect (G_OBJECT (plugin->generator), "error",
480 				                  G_CALLBACK (cg_plugin_generator_error_cb),
481 				                  plugin);
482 
483 				g_signal_connect (G_OBJECT (plugin->generator), "created",
484 				                 G_CALLBACK (cg_plugin_generator_created_cb),
485 								 plugin);
486 
487 				gtk_widget_set_sensitive (
488 					GTK_WIDGET (cg_window_get_dialog (plugin->window)), FALSE);
489 			}
490 
491 			g_hash_table_destroy (values);
492 			g_free (header_file);
493 			g_free (source_file);
494 		}
495 	}
496 	else
497 	{
498 		g_object_unref (G_OBJECT (plugin->window));
499 		plugin->window = NULL;
500 	}
501 }
502 
503 #define PREF_SCHEMA "org.gnome.anjuta"
504 
505 static void
iwizard_activate(IAnjutaWizard * wiz,G_GNUC_UNUSED GError ** err)506 iwizard_activate (IAnjutaWizard *wiz, G_GNUC_UNUSED GError **err)
507 {
508 	/* IAnjutaProjectManager *pm; */
509 	AnjutaClassGenPlugin *cg_plugin;
510 	gchar *user_name;
511 	gchar *user_email;
512 	gint caps = 0;
513 	gboolean has_project;
514 
515 	cg_plugin = ANJUTA_PLUGIN_CLASS_GEN (wiz);
516 
517 	if (cg_plugin->window != NULL)
518 		g_object_unref (G_OBJECT (cg_plugin->window));
519 
520 	cg_plugin->window = cg_window_new ();
521 
522 	user_name = g_strdup(g_get_real_name ());
523 	/* FIXME: */
524 	user_email = anjuta_util_get_user_mail();
525 
526 	if (user_name != NULL)
527 		cg_window_set_author (cg_plugin->window, user_name);
528 
529 	if (user_email != NULL)
530 		cg_window_set_email (cg_plugin->window, user_email);
531 
532 	g_free(user_name);
533 	g_free(user_email);
534 
535 	/* Check whether we have a loaded project and it can add sources */
536 	if (cg_plugin->top_dir)
537 	{
538 		IAnjutaProjectManager *manager =
539 			anjuta_shell_get_interface (ANJUTA_PLUGIN (wiz)->shell,
540 										IAnjutaProjectManager, NULL);
541 		if (manager)
542 		{
543 			caps = ianjuta_project_manager_get_capabilities (manager, NULL);
544 			cg_window_set_project_model (cg_plugin->window, manager);
545 		}
546 	}
547 
548 	has_project = (caps & ANJUTA_PROJECT_CAN_ADD_SOURCE) ? TRUE : FALSE;
549 	cg_window_set_add_to_project (cg_plugin->window, has_project);
550 	cg_window_enable_add_to_project (cg_plugin->window, has_project);
551 
552 	/* TODO: Check whether the project is in version control, and enable
553 	 * "add to repository" button respectively. */
554 
555 	g_signal_connect (G_OBJECT (cg_window_get_dialog(cg_plugin->window)),
556 	                 "response", G_CALLBACK (cg_plugin_window_response_cb),
557 					 cg_plugin);
558 
559 	gtk_widget_show (GTK_WIDGET (cg_window_get_dialog (cg_plugin->window)));
560 }
561 
562 static void
iwizard_iface_init(IAnjutaWizardIface * iface)563 iwizard_iface_init (IAnjutaWizardIface *iface)
564 {
565 	iface->activate = iwizard_activate;
566 }
567 
568 ANJUTA_PLUGIN_BEGIN (AnjutaClassGenPlugin, class_gen_plugin);
569 ANJUTA_PLUGIN_ADD_INTERFACE(iwizard, IANJUTA_TYPE_WIZARD);
570 ANJUTA_PLUGIN_END;
571 
572 ANJUTA_SIMPLE_PLUGIN (AnjutaClassGenPlugin, class_gen_plugin);
573