project-import: Open a directory with Anjuta
[anjuta.git] / plugins / project-import / plugin.c
blob15802799b485a016fa5ec8161b942e5f1bcc3cd1
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 plugin.c
4 Copyright (C) 2000 Naba Kumar, 2005 Johannes Schmid
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include <config.h>
22 #include <gtk/gtk.h>
23 #include <glib/gi18n.h>
24 #include <libanjuta/anjuta-debug.h>
25 #include <libanjuta/anjuta-utils.h>
26 #include <libanjuta/interfaces/ianjuta-wizard.h>
27 #include <libanjuta/interfaces/ianjuta-file.h>
28 #include <libanjuta/interfaces/ianjuta-file-loader.h>
29 #include <libanjuta/interfaces/ianjuta-project-backend.h>
30 #include <libanjuta/interfaces/ianjuta-vcs.h>
31 #include <libanjuta/anjuta-async-notify.h>
33 #include "plugin.h"
34 #include "project-import-dialog.h"
36 #define ICON_FILE "anjuta-project-import-plugin-48.png"
38 #define AM_PROJECT_FILE PACKAGE_DATA_DIR"/project/terminal/project.anjuta"
39 #define MKFILE_PROJECT_FILE PACKAGE_DATA_DIR"/project/mkfile/project.anjuta"
40 #define DIRECTORY_PROJECT_FILE PACKAGE_DATA_DIR"/project/directory/project.anjuta"
42 static gpointer parent_class;
44 static gboolean
45 project_import_generate_file (AnjutaPluginDescription *backend, ProjectImportDialog *import_dialog,
46 GFile *project_file)
48 /* Of course we could do some more intelligent stuff here
49 * and check which plugins are really needed */
51 GFile* source_file = NULL;
52 gchar *backend_id = NULL;
53 GError* error = NULL;
55 if (!anjuta_plugin_description_get_string (backend, "Project", "Supported-Project-Types", &backend_id))
57 if (!strcmp (backend_id, "automake"))
58 source_file = g_file_new_for_path (AM_PROJECT_FILE);
59 else if (!strcmp (backend_id, "make"))
60 source_file = g_file_new_for_path (MKFILE_PROJECT_FILE);
61 else if (!strcmp (backend_id, "directory"))
62 source_file = g_file_new_for_path (DIRECTORY_PROJECT_FILE);
64 g_free (backend_id);
66 if (source_file != NULL)
68 /* Use a default project file */
69 if (!g_file_copy (source_file, project_file,
70 G_FILE_COPY_NONE,
71 NULL,
72 NULL,
73 NULL,
74 &error))
76 if (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_EXISTS)
78 gchar *prjfile = g_file_get_parse_name (project_file);
79 if (anjuta_util_dialog_boolean_question (GTK_WINDOW (import_dialog), FALSE,
80 _("A file named \"%s\" already exists. "
81 "Do you want to replace it?"), prjfile))
83 g_error_free (error);
84 error = NULL;
85 g_file_copy (source_file, project_file,
86 G_FILE_COPY_OVERWRITE,
87 NULL,
88 NULL,
89 NULL,
90 &error);
92 g_free (prjfile);
96 if (!error)
98 time_t ctime = time(NULL);
99 GFileInfo* file_info = g_file_info_new();
100 g_file_info_set_attribute_uint64(file_info,
101 "time::modified",
102 ctime);
103 g_file_info_set_attribute_uint64(file_info,
104 "time::created",
105 ctime);
106 g_file_info_set_attribute_uint64(file_info,
107 "time::access",
108 ctime);
109 g_file_set_attributes_from_info (project_file,
110 file_info,
111 G_FILE_QUERY_INFO_NONE,
112 NULL, NULL);
114 g_object_unref (G_OBJECT(file_info));;
117 else
119 /* For unknown project backend we use the directory project file and
120 * replace the backend plugin with the right one */
122 gchar *content;
123 gsize length;
125 source_file = g_file_new_for_path (DIRECTORY_PROJECT_FILE);
126 if (g_file_load_contents (source_file, NULL, &content, &length, NULL, &error))
128 GString *buffer;
129 const gchar *pos;
130 const gchar *plugin;
131 const gchar *end_plugin;
132 gssize len;
134 buffer = g_string_new_len (content, length);
135 pos = buffer->str;
136 len = buffer->len;
137 for (;;)
139 plugin = g_strstr_len (pos, len, "<plugin ");
140 if (plugin == NULL) break;
142 end_plugin = g_strstr_len (plugin, len - (plugin - pos), "</plugin>");
143 if (end_plugin == NULL) break;
145 if (g_strstr_len (plugin, end_plugin - plugin, "\"IAnjutaProjectBackend\"") != NULL) break;
147 pos = end_plugin + 9;
148 len -= (end_plugin + 9 - pos);
151 if ((plugin == NULL) || (end_plugin == NULL))
153 g_set_error (&error, ianjuta_project_backend_error_quark(),0, "Unable to find backend plugin");
155 else
157 /* Replace directory backend with right one */
158 GString *str;
159 GFileOutputStream *stream;
160 gchar *name = NULL;
161 gchar *plugin_id = NULL;
163 anjuta_plugin_description_get_string (backend, "Anjuta Plugin", "Name", &name);
164 anjuta_plugin_description_get_string (backend, "Anjuta Plugin", "Location", &plugin_id);
166 str = g_string_new (NULL);
167 g_string_printf (str, "<plugin name= \"%s\"\n"
168 " mandatory=\"yes\">\n"
169 " <require group=\"Anjuta Plugin\"\n"
170 " attribute=\"Location\"\n"
171 " value=\"%s\"/>\n"
172 " <require group=\"Anjuta Plugin\"\n"
173 " attribute=\"Interfaces\"\n"
174 " value=\"IAnjutaProjectBackend\"/>\n"
175 " ", name, plugin_id);
177 g_string_erase (buffer, plugin - buffer->str, end_plugin - plugin);
178 g_string_insert_len (buffer, plugin - buffer->str, str->str, str->len);
180 g_string_free (str, TRUE);
182 stream = g_file_create (project_file, G_FILE_CREATE_NONE, NULL, &error);
183 if (stream == NULL && error->domain == G_IO_ERROR && error->code == G_IO_ERROR_EXISTS)
185 gchar *prjfile = g_file_get_parse_name (project_file);
186 if (anjuta_util_dialog_boolean_question (GTK_WINDOW (import_dialog), FALSE,
187 _("A file named \"%s\" already exists. "
188 "Do you want to replace it?"), prjfile))
190 g_error_free (error);
191 error = NULL;
192 stream = g_file_replace (project_file, NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL, &error);
194 g_free (prjfile);
197 if (stream != NULL)
199 gsize written;
201 g_output_stream_write_all (G_OUTPUT_STREAM (stream), buffer->str, buffer->len, &written, NULL, &error);
202 g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, NULL);
206 g_string_free (buffer, TRUE);
207 g_free (content);
210 g_object_unref (source_file);
212 if (error)
214 gchar *prjfile;
216 prjfile = g_file_get_parse_name (project_file);
218 /* show the dialog since it may be hidden */
219 gtk_widget_show (GTK_WIDGET (import_dialog));
221 anjuta_util_dialog_error (GTK_WINDOW (import_dialog),
222 _("A file named \"%s\" cannot be written: %s. "
223 "Check if you have write access to the project directory."),
224 prjfile, error->message);
225 g_free (prjfile);
226 g_error_free (error);
228 return FALSE;
232 return TRUE;
235 static gboolean
236 project_import_import_project (AnjutaProjectImportPlugin *import_plugin, ProjectImportDialog *import_dialog,
237 GFile *source_dir)
239 AnjutaPluginManager *plugin_manager;
240 GList *descs = NULL;
241 GList *desc;
242 AnjutaPluginDescription *backend;
243 gchar *name, *project_file_name;
245 /* Search for all valid project backend */
246 plugin_manager = anjuta_shell_get_plugin_manager (ANJUTA_PLUGIN(import_plugin)->shell, NULL);
247 descs = anjuta_plugin_manager_query (plugin_manager,
248 "Anjuta Plugin",
249 "Interfaces",
250 "IAnjutaProjectBackend",
251 NULL);
252 for (desc = g_list_first (descs); desc != NULL;) {
253 IAnjutaProjectBackend *plugin;
254 gchar *location = NULL;
255 GList *next;
257 backend = (AnjutaPluginDescription *)desc->data;
258 anjuta_plugin_description_get_string (backend, "Anjuta Plugin", "Location", &location);
259 plugin = (IAnjutaProjectBackend *)anjuta_plugin_manager_get_plugin_by_id (plugin_manager, location);
260 g_free (location);
262 next = g_list_next (desc);
264 /* Probe the project directory to find if the backend can handle it */
265 if (ianjuta_project_backend_probe (plugin, source_dir, NULL) <= 0)
267 /* Remove invalid backend */
268 descs = g_list_delete_link (descs, desc);
271 desc = next;
274 if (descs == NULL)
276 backend = NULL;
278 else if (g_list_next (descs) == NULL)
280 backend = (AnjutaPluginDescription *)descs->data;
282 else
284 /* Several backend are possible, ask the user to select one */
285 gchar *path = project_import_dialog_get_name (import_dialog);
286 gchar* message = g_strdup_printf (_("Please select a project backend to open %s."), path);
288 g_free (path);
290 backend = anjuta_plugin_manager_select (plugin_manager,
291 _("Open With"),
292 message,
293 descs);
294 g_free (message);
296 g_list_free (descs);
298 if (backend == NULL)
300 gchar *path = project_import_dialog_get_name (import_dialog);
302 /* show the dialog since it may be hidden */
303 gtk_widget_show (GTK_WIDGET (import_dialog));
305 anjuta_util_dialog_error (GTK_WINDOW (import_dialog),
306 _("Could not find a valid project backend for the "
307 "given directory (%s). Please select a different "
308 "directory, or try upgrading to a newer version of "
309 "Anjuta."), path);
311 g_free (path);
313 return FALSE;
317 name = project_import_dialog_get_name (import_dialog);
318 project_file_name = g_strconcat (name, ".", "anjuta", NULL);
319 GFile *project_file = g_file_get_child (source_dir, project_file_name);
321 g_free (name);
322 g_free (project_file_name);
324 IAnjutaFileLoader* loader;
326 if (!project_import_generate_file (backend, import_dialog, project_file))
328 g_object_unref (project_file);
329 return FALSE;
332 loader = anjuta_shell_get_interface (ANJUTA_PLUGIN (import_plugin)->shell,
333 IAnjutaFileLoader, NULL);
334 if (!loader)
336 g_warning("No IAnjutaFileLoader interface! Cannot open project file!");
337 g_object_unref (project_file);
338 return TRUE;
341 ianjuta_file_loader_load (loader, project_file, FALSE, NULL);
343 g_object_unref (project_file);
345 return TRUE;
348 typedef struct
350 AnjutaProjectImportPlugin *import_plugin;
351 ProjectImportDialog *import_dialog;
352 GFile *checkout_dir;
353 } CheckoutData;
355 static void
356 checkout_finished (AnjutaAsyncNotify *async_notify, gpointer user_data)
358 CheckoutData *ch = (CheckoutData *)user_data;
359 GError *err;
361 err = NULL;
362 anjuta_async_notify_get_error (async_notify, &err);
363 if (err)
365 gchar *vcs_uri;
367 /* show the dialog since it's hidden */
368 gtk_widget_show (GTK_WIDGET (ch->import_dialog));
370 vcs_uri = project_import_dialog_get_vcs_uri (ch->import_dialog);
371 anjuta_util_dialog_error (GTK_WINDOW (ch->import_dialog),
372 _("Couldn't check out the supplied URI "
373 "\"%s\". The error returned was: \"%s\""),
374 vcs_uri, err->message);
376 g_free (vcs_uri);
377 g_error_free (err);
379 goto cleanup;
382 project_import_import_project (ch->import_plugin, ch->import_dialog, ch->checkout_dir);
384 cleanup:
385 g_object_unref (ch->checkout_dir);
386 g_slice_free (CheckoutData, ch);
389 static void
390 project_import_checkout_project (AnjutaProjectImportPlugin *import_plugin,
391 ProjectImportDialog *import_dialog)
393 CheckoutData *ch_data;
394 AnjutaAsyncNotify *async_notify;
395 gchar *vcs_uri, *plugin_id, *name;
396 GFile *dest_dir, *checkout_dir;
397 AnjutaPluginManager *plugin_manager;
398 IAnjutaVcs *ivcs;
399 GError *err;
401 name = project_import_dialog_get_name (import_dialog);
402 dest_dir = project_import_dialog_get_dest_dir (import_dialog);
403 checkout_dir = g_file_get_child (dest_dir, name);
405 g_object_unref (dest_dir);
406 g_free (name);
408 ch_data = g_slice_new (CheckoutData);
409 ch_data->import_plugin = import_plugin;
410 ch_data->import_dialog = import_dialog;
411 ch_data->checkout_dir = checkout_dir;
413 async_notify = anjuta_async_notify_new ();
414 g_signal_connect (async_notify, "finished", G_CALLBACK (checkout_finished),
415 ch_data);
417 vcs_uri = project_import_dialog_get_vcs_uri (import_dialog);
418 plugin_id = project_import_dialog_get_vcs_id (import_dialog);
420 plugin_manager = anjuta_shell_get_plugin_manager (ANJUTA_PLUGIN (import_plugin)->shell, NULL);
421 ivcs = IANJUTA_VCS (anjuta_plugin_manager_get_plugin_by_id (plugin_manager, plugin_id));
423 err = NULL;
424 ianjuta_vcs_checkout (ivcs, vcs_uri, checkout_dir, NULL, async_notify, &err);
425 if (err)
427 anjuta_util_dialog_error (GTK_WINDOW (import_dialog),
428 _("Couldn't check out the supplied URI "
429 "\"%s\". The error returned was: \"%s\""),
430 vcs_uri, err->message);
432 g_error_free (err);
434 goto cleanup;
437 /* hide the import dialog */
438 gtk_widget_hide (GTK_WIDGET (import_dialog));
440 cleanup:
441 g_free (vcs_uri);
442 g_free (plugin_id);
445 static void
446 import_dialog_response (GtkDialog *dialog, gint response_id, gpointer user_data)
448 AnjutaProjectImportPlugin *import_plugin = (AnjutaProjectImportPlugin *)user_data;
449 ProjectImportDialog *import_dialog = PROJECT_IMPORT_DIALOG (dialog);
451 switch (response_id)
453 case GTK_RESPONSE_ACCEPT:
455 GFile *source_dir;
457 source_dir = project_import_dialog_get_source_dir (import_dialog);
458 if (source_dir)
460 if (project_import_import_project (import_plugin, import_dialog, source_dir))
461 gtk_widget_destroy (GTK_WIDGET (import_dialog));
463 g_object_unref (source_dir);
465 else
466 project_import_checkout_project (import_plugin, import_dialog);
468 break;
471 case GTK_RESPONSE_REJECT:
472 gtk_widget_destroy (GTK_WIDGET (dialog));
476 static gboolean
477 activate_plugin (AnjutaPlugin *plugin)
479 AnjutaProjectImportPlugin *iplugin;
481 DEBUG_PRINT ("%s", "AnjutaProjectImportPlugin: Activating Project Import Plugin ...");
483 iplugin = ANJUTA_PLUGIN_PROJECT_IMPORT (plugin);
484 iplugin->prefs = anjuta_shell_get_preferences (plugin->shell, NULL);
486 return TRUE;
489 static gboolean
490 deactivate_plugin (AnjutaPlugin *plugin)
492 return TRUE;
495 static void
496 dispose (GObject *obj)
498 G_OBJECT_CLASS (parent_class)->dispose (obj);
501 static void
502 finalize (GObject *obj)
504 G_OBJECT_CLASS (parent_class)->finalize (obj);
507 static void
508 project_import_plugin_instance_init (GObject *obj)
510 // AnjutaFileWizardPlugin *plugin = ANJUTA_PLUGIN_PROJECT_IMPORT (obj);
513 static void
514 project_import_plugin_class_init (GObjectClass *klass)
516 AnjutaPluginClass *plugin_class = ANJUTA_PLUGIN_CLASS (klass);
518 parent_class = g_type_class_peek_parent (klass);
520 plugin_class->activate = activate_plugin;
521 plugin_class->deactivate = deactivate_plugin;
522 klass->dispose = dispose;
523 klass->finalize = finalize;
526 static void
527 iwizard_activate (IAnjutaWizard *wiz, GError **err)
529 AnjutaProjectImportPlugin* plugin = ANJUTA_PLUGIN_PROJECT_IMPORT (wiz);
530 AnjutaPluginManager *plugin_manager;
531 ProjectImportDialog* pi;
533 plugin_manager = anjuta_shell_get_plugin_manager (ANJUTA_PLUGIN (plugin)->shell, NULL);
535 pi = project_import_dialog_new(plugin_manager, NULL, NULL);
536 g_signal_connect (pi, "response", G_CALLBACK (import_dialog_response), plugin);
538 gtk_widget_show (GTK_WIDGET (pi));
541 static void
542 iwizard_iface_init (IAnjutaWizardIface *iface)
544 iface->activate = iwizard_activate;
547 static void
548 ifile_open (IAnjutaFile *ifile, GFile* file, GError **err)
550 AnjutaProjectImportPlugin* plugin = ANJUTA_PLUGIN_PROJECT_IMPORT (ifile);
551 gchar *mime_type;
553 g_return_if_fail (G_IS_FILE (file));
555 mime_type = anjuta_util_get_file_mime_type (file);
556 if (g_strcmp0 (mime_type,"application/x-anjuta-old") == 0)
558 /* Automatically import old Anjuta project */
559 gchar *ext, *project_name;
560 GFile *dir;
561 ProjectImportDialog* pi;
562 AnjutaPluginManager *plugin_manager;
564 dir = g_file_get_parent (file);
565 project_name = g_file_get_basename (file);
566 ext = strrchr (project_name, '.');
567 if (ext)
568 *ext = '\0';
570 plugin_manager = anjuta_shell_get_plugin_manager (ANJUTA_PLUGIN (plugin)->shell, NULL);
572 pi = project_import_dialog_new (plugin_manager, project_name, dir);
573 g_signal_connect (pi, "response", G_CALLBACK (import_dialog_response), plugin);
575 gtk_widget_show (GTK_WIDGET (pi));
577 g_object_unref (dir);
578 g_free (project_name);
580 else if (g_strcmp0 (mime_type,"inode/directory") == 0)
582 GFileEnumerator *dir;
584 dir = g_file_enumerate_children (file,
585 G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
586 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
587 NULL,
588 NULL);
589 if (dir)
591 /* Look for anjuta project file in the directory */
592 GFileInfo *info;
594 for (info = g_file_enumerator_next_file (dir, NULL, NULL); info != NULL; info = g_file_enumerator_next_file (dir, NULL, NULL))
596 gchar *mime_type = anjuta_util_get_file_info_mime_type (info);
598 if (g_strcmp0 (mime_type, "application/x-anjuta") == 0)
600 /* Open the first anjuta project file */
601 IAnjutaFileLoader *loader;
603 loader = anjuta_shell_get_interface(ANJUTA_PLUGIN (plugin)->shell, IAnjutaFileLoader, NULL);
604 if (loader != NULL)
606 GFile* project_file = g_file_get_child (file, g_file_info_get_name(info));
607 ianjuta_file_loader_load(loader, project_file, FALSE, NULL);
608 g_object_unref (project_file);
610 g_free (mime_type);
611 g_object_unref (info);
612 break;
614 g_free (mime_type);
615 g_object_unref (info);
617 if (info == NULL)
619 /* Else import the directory */
620 ProjectImportDialog* pi;
621 AnjutaPluginManager *plugin_manager;
622 gchar *basename;
624 plugin_manager = anjuta_shell_get_plugin_manager (ANJUTA_PLUGIN (plugin)->shell, NULL);
626 basename = g_file_get_basename (file);
627 pi = project_import_dialog_new (plugin_manager, basename, file);
628 g_free (basename);
629 g_signal_connect (pi, "response", G_CALLBACK (import_dialog_response), plugin);
631 gtk_widget_show (GTK_WIDGET (pi));
633 g_object_unref (dir);
636 g_free (mime_type);
639 static GFile*
640 ifile_get_file (IAnjutaFile *file, GError **err)
642 g_warning ("Unsupported operation");
643 return NULL;
646 static void
647 ifile_iface_init (IAnjutaFileIface *iface)
649 iface->open = ifile_open;
650 iface->get_file = ifile_get_file;
653 ANJUTA_PLUGIN_BEGIN (AnjutaProjectImportPlugin, project_import_plugin);
654 ANJUTA_PLUGIN_ADD_INTERFACE(iwizard, IANJUTA_TYPE_WIZARD);
655 ANJUTA_PLUGIN_ADD_INTERFACE(ifile, IANJUTA_TYPE_FILE);
656 ANJUTA_PLUGIN_END;
658 ANJUTA_SIMPLE_PLUGIN (AnjutaProjectImportPlugin, project_import_plugin);