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