1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4 * Copyright (C) Ishan Chattopadhyaya 2009 <ichattopadhyaya@gmail.com>
6 * plugin.c is free software.
8 * You may redistribute it and/or modify it under the terms of the
9 * GNU General Public License, as published by the Free Software
10 * Foundation; either version 2 of the License, or (at your option)
13 * plugin.c 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.
16 * See the GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with plugin.c. If not, write to:
20 * The Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor
22 * Boston, MA 02110-1301, USA.
28 #include <libanjuta/anjuta-shell.h>
29 #include <libanjuta/anjuta-debug.h>
30 #include <libanjuta/anjuta-launcher.h>
31 #include <libanjuta/anjuta-preferences.h>
32 #include <libanjuta/anjuta-utils.h>
33 #include <libanjuta/interfaces/ianjuta-iterable.h>
34 #include <libanjuta/interfaces/ianjuta-document.h>
35 #include <libanjuta/interfaces/ianjuta-document-manager.h>
36 #include <libanjuta/interfaces/ianjuta-editor.h>
37 #include <libanjuta/interfaces/ianjuta-editor-cell.h>
38 #include <libanjuta/interfaces/ianjuta-editor-language.h>
39 #include <libanjuta/interfaces/ianjuta-editor-selection.h>
40 #include <libanjuta/interfaces/ianjuta-editor-assist.h>
41 #include <libanjuta/interfaces/ianjuta-editor-glade-signal.h>
42 #include <libanjuta/interfaces/ianjuta-preferences.h>
43 #include <libanjuta/interfaces/ianjuta-symbol.h>
44 #include <libanjuta/interfaces/ianjuta-language.h>
45 #include <libanjuta/interfaces/ianjuta-indenter.h>
48 #include "python-assist.h"
50 #define UI_FILE PACKAGE_DATA_DIR"/ui/anjuta-language-support-python.xml"
51 #define PROPERTIES_FILE_UI PACKAGE_DATA_DIR"/glade/anjuta-language-support-python.ui"
52 #define ICON_FILE "anjuta-language-support-python-plugin.png"
54 /* Preferences keys */
56 #define ANJUTA_PREF_SCHEMA_PREFIX "org.gnome.anjuta."
57 #define PREF_SCHEMA "org.gnome.anjuta.plugins.python"
60 #define PREF_NO_ROPE_WARNING "no-rope-warning"
61 #define PREF_INTERPRETER_PATH "interpreter-path"
63 static gpointer parent_class
;
66 on_check_finished (AnjutaLauncher
* launcher
,
67 int child_pid
, int exit_status
,
68 gulong time
, gpointer user_data
)
70 PythonPlugin
* plugin
= ANJUTA_PLUGIN_PYTHON (user_data
);
73 GtkWidget
* dialog
= gtk_dialog_new_with_buttons (_("Python support warning"),
79 GtkWidget
* area
= gtk_dialog_get_content_area (GTK_DIALOG (dialog
));
81 GtkWidget
* label
= gtk_label_new (_("Either python path is wrong or python-rope (http://rope.sf.net) libraries\n"
82 "aren't installed. Both are required for autocompletion in python files.\n"
83 "Please install them and check the python path in the preferences."));
84 GtkWidget
* check_button
= gtk_check_button_new_with_label (_("Do not show that warning again"));
86 gtk_box_pack_start (GTK_BOX (area
), label
,
88 gtk_box_pack_start (GTK_BOX (area
), check_button
,
90 gtk_widget_show_all (dialog
);
92 gtk_dialog_run (GTK_DIALOG(dialog
));
94 /* Save "Do not show again settings" */
95 g_settings_set_boolean (plugin
->settings
,
97 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check_button
)));
99 gtk_widget_destroy (dialog
);
101 g_object_unref (launcher
);
105 check_support (PythonPlugin
*python_plugin
)
107 if (!g_settings_get_boolean (python_plugin
->settings
,
108 PREF_NO_ROPE_WARNING
))
110 AnjutaLauncher
* launcher
= anjuta_launcher_new ();
111 gchar
* python_path
= g_settings_get_string (python_plugin
->settings
,
112 PREF_INTERPRETER_PATH
);
113 gchar
* command
= g_strdup_printf ("%s -c \"import rope\"", python_path
);
115 g_signal_connect (launcher
, "child-exited",
116 G_CALLBACK(on_check_finished
), python_plugin
);
117 anjuta_launcher_execute (launcher
, command
, NULL
, NULL
);
119 g_free (python_path
);
126 language_support_check_param_name (const gchar
* name
,
130 GString
* real_name
= g_string_new (name
);
131 while (g_list_find_custom (*names
, real_name
->str
, (GCompareFunc
) strcmp
))
133 g_string_free (real_name
, TRUE
);
134 real_name
= g_string_new (name
);
135 g_string_append_printf (real_name
, "%d", ++index
);
137 *names
= g_list_append (*names
, real_name
->str
);
138 return g_string_free (real_name
, FALSE
);
142 language_support_get_signal_parameter (const gchar
* type_name
, GList
** names
)
145 const gchar
* param_name
= NULL
;
146 GString
* param_string
;
148 /* Search for the second upper character */
149 for (c
= type_name
+ 1; *c
!= '\0'; c
++)
151 if (g_ascii_isupper (*c
))
157 if (param_name
&& strlen (param_name
))
159 param_string
= g_string_new (param_name
);
160 g_string_ascii_down (param_string
);
164 param_string
= g_string_new ("arg");
166 real_name
= language_support_check_param_name (g_string_free (param_string
, FALSE
), names
);
172 on_glade_drop (IAnjutaEditor
* editor
,
173 IAnjutaIterable
* iterator
,
174 const gchar
* signal_data
,
175 PythonPlugin
* lang_plugin
)
183 const gchar
* handler
;
185 GString
* str
= g_string_new (NULL
);
187 IAnjutaIterable
* start
, * end
;
189 GStrv data
= g_strsplit(signal_data
, ":", 5);
195 type
= g_type_from_name (widget
);
196 id
= g_signal_lookup (signal
, type
);
198 g_signal_query (id
, &query
);
200 g_string_append_printf (str
, "\ndef %s (self, %s", handler
,
201 language_support_get_signal_parameter (widget
,
203 for (i
= 0; i
< query
.n_params
; i
++)
205 const gchar
* type_name
= g_type_name (query
.param_types
[i
]);
206 const gchar
* param_name
= language_support_get_signal_parameter (type_name
,
209 g_string_append_printf (str
, ", %s", param_name
);
211 g_string_append (str
, "):\n");
213 ianjuta_editor_insert (editor
, iterator
,
216 /* Indent code correctly */
218 end
= ianjuta_iterable_clone (iterator
, NULL
);
219 ianjuta_iterable_set_position (end
,
220 ianjuta_iterable_get_position (iterator
, NULL
)
221 + g_utf8_strlen (str
->str
, -1),
223 ianjuta_indenter_indent (IANJUTA_INDENTER (lang_plugin
),
225 g_object_unref (end
);
227 g_string_free (str
, TRUE
);
228 anjuta_util_glist_strings_free (names
);
234 install_support (PythonPlugin
*lang_plugin
)
236 IAnjutaLanguage
* lang_manager
=
237 anjuta_shell_get_interface (ANJUTA_PLUGIN (lang_plugin
)->shell
,
238 IAnjutaLanguage
, NULL
);
239 IAnjutaSymbolManager
* sym_manager
=
240 anjuta_shell_get_interface (ANJUTA_PLUGIN (lang_plugin
)->shell
,
241 IAnjutaSymbolManager
,
244 if (!lang_manager
|| !sym_manager
)
247 if (lang_plugin
->support_installed
)
250 lang_plugin
->current_language
=
251 ianjuta_language_get_name_from_editor (lang_manager
,
252 IANJUTA_EDITOR_LANGUAGE (lang_plugin
->current_editor
), NULL
);
254 if (!(lang_plugin
->current_language
&&
255 (g_str_equal (lang_plugin
->current_language
, "Python"))))
258 /* Disable editor intern auto-indent */
259 ianjuta_editor_set_auto_indent (IANJUTA_EDITOR(lang_plugin
->current_editor
),
262 if (IANJUTA_IS_EDITOR_ASSIST (lang_plugin
->current_editor
) )
264 AnjutaPlugin
*plugin
;
265 IAnjutaEditor
* ieditor
;
267 const gchar
*project_root
;
269 check_support (lang_plugin
);
271 plugin
= ANJUTA_PLUGIN (lang_plugin
);
272 ieditor
= IANJUTA_EDITOR (lang_plugin
->current_editor
);
274 g_assert (lang_plugin
->assist
== NULL
);
276 project_root
= ANJUTA_PLUGIN_PYTHON(plugin
)->project_root_directory
;
278 lang_plugin
->assist
= python_assist_new (ieditor
,
280 lang_plugin
->settings
,
285 if (IANJUTA_IS_EDITOR_GLADE_SIGNAL (lang_plugin
->current_editor
))
287 g_signal_connect (lang_plugin
->current_editor
,
288 "drop-possible", G_CALLBACK (gtk_true
), NULL
);
289 g_signal_connect (lang_plugin
->current_editor
,
290 "drop", G_CALLBACK (on_glade_drop
),
294 lang_plugin
->support_installed
= TRUE
;
298 uninstall_support (PythonPlugin
*lang_plugin
)
300 if (!lang_plugin
->support_installed
)
303 if (lang_plugin
->assist
)
305 g_object_unref (lang_plugin
->assist
);
306 lang_plugin
->assist
= NULL
;
309 if (IANJUTA_IS_EDITOR_GLADE_SIGNAL (lang_plugin
->current_editor
))
311 g_signal_handlers_disconnect_by_func (lang_plugin
->current_editor
,
313 g_signal_handlers_disconnect_by_func (lang_plugin
->current_editor
,
314 on_glade_drop
, lang_plugin
);
317 lang_plugin
->support_installed
= FALSE
;
321 on_editor_language_changed (IAnjutaEditor
*editor
,
322 const gchar
*new_language
,
323 PythonPlugin
*plugin
)
325 uninstall_support (plugin
);
326 install_support (plugin
);
330 on_editor_added (AnjutaPlugin
*plugin
, const gchar
*name
,
331 const GValue
*value
, gpointer data
)
333 PythonPlugin
*lang_plugin
;
334 IAnjutaDocument
* doc
= IANJUTA_DOCUMENT(g_value_get_object (value
));
335 lang_plugin
= ANJUTA_PLUGIN_PYTHON(plugin
);
338 if (IANJUTA_IS_EDITOR(doc
))
340 lang_plugin
->current_editor
= G_OBJECT(doc
);
344 lang_plugin
->current_editor
= NULL
;
347 if (lang_plugin
->current_editor
)
349 install_support (lang_plugin
);
350 g_signal_connect (lang_plugin
->current_editor
, "language-changed",
351 G_CALLBACK (on_editor_language_changed
),
357 on_editor_removed (AnjutaPlugin
*plugin
, const gchar
*name
,
360 PythonPlugin
*lang_plugin
;
361 lang_plugin
= ANJUTA_PLUGIN_PYTHON (plugin
);
363 if (lang_plugin
->current_editor
)
364 g_signal_handlers_disconnect_by_func (lang_plugin
->current_editor
,
365 G_CALLBACK (on_editor_language_changed
),
368 uninstall_support (lang_plugin
);
370 lang_plugin
->current_editor
= NULL
;
371 lang_plugin
->current_language
= NULL
;
374 static GtkActionEntry actions
[] = {
383 on_project_root_added (AnjutaPlugin
*plugin
, const gchar
*name
,
384 const GValue
*value
, gpointer user_data
)
386 PythonPlugin
*python_plugin
;
387 gchar
*project_root_uri
;
390 python_plugin
= ANJUTA_PLUGIN_PYTHON (plugin
);
392 g_free (python_plugin
->project_root_directory
);
393 project_root_uri
= g_value_dup_string (value
);
394 file
= g_file_new_for_uri (project_root_uri
);
395 python_plugin
->project_root_directory
= g_file_get_path (file
);
396 g_object_unref (file
);
397 g_free (project_root_uri
);
401 on_project_root_removed (AnjutaPlugin
*plugin
, const gchar
*name
,
404 PythonPlugin
*python_plugin
;
406 python_plugin
= ANJUTA_PLUGIN_PYTHON (plugin
);
408 g_free (python_plugin
->project_root_directory
);
409 python_plugin
->project_root_directory
= NULL
;
413 python_plugin_activate (AnjutaPlugin
*plugin
)
417 PythonPlugin
*python_plugin
;
419 python_plugin
= (PythonPlugin
*) plugin
;
421 python_plugin
->prefs
= anjuta_shell_get_preferences (plugin
->shell
, NULL
);
423 /* Add all UI actions and merge UI */
424 ui
= anjuta_shell_get_ui (plugin
->shell
, NULL
);
426 python_plugin
->action_group
=
427 anjuta_ui_add_action_group_entries (ui
, "ActionGroupPythonAssist",
428 _("Python Assistance"),
430 G_N_ELEMENTS (actions
),
431 GETTEXT_PACKAGE
, TRUE
,
433 python_plugin
->uiid
= anjuta_ui_merge (ui
, UI_FILE
);
436 python_plugin
->project_root_watch_id
= anjuta_plugin_add_watch (plugin
,
437 IANJUTA_PROJECT_MANAGER_PROJECT_ROOT_URI
,
438 on_project_root_added
,
439 on_project_root_removed
,
442 python_plugin
->editor_watch_id
= anjuta_plugin_add_watch (plugin
,
443 IANJUTA_DOCUMENT_MANAGER_CURRENT_DOCUMENT
,
451 python_plugin_deactivate (AnjutaPlugin
*plugin
)
455 PythonPlugin
*lang_plugin
;
456 lang_plugin
= (PythonPlugin
*) (plugin
);
458 anjuta_plugin_remove_watch (plugin
,
459 lang_plugin
->editor_watch_id
,
461 anjuta_plugin_remove_watch (plugin
,
462 lang_plugin
->project_root_watch_id
,
466 ui
= anjuta_shell_get_ui (plugin
->shell
, NULL
);
467 anjuta_ui_remove_action_group (ui
, ANJUTA_PLUGIN_PYTHON(plugin
)->action_group
);
468 anjuta_ui_unmerge (ui
, ANJUTA_PLUGIN_PYTHON(plugin
)->uiid
);
474 python_plugin_finalize (GObject
*obj
)
476 /* Finalization codes here */
477 G_OBJECT_CLASS (parent_class
)->finalize (obj
);
481 python_plugin_dispose (GObject
*obj
)
483 /* Disposition codes */
484 PythonPlugin
*plugin
= (PythonPlugin
*)obj
;
486 if (plugin
->settings
)
487 g_object_unref (plugin
->settings
);
488 plugin
->settings
= NULL
;
490 G_OBJECT_CLASS (parent_class
)->dispose (obj
);
494 python_plugin_instance_init (GObject
*obj
)
496 PythonPlugin
*plugin
= (PythonPlugin
*)obj
;
497 plugin
->action_group
= NULL
;
498 plugin
->current_editor
= NULL
;
499 plugin
->current_language
= NULL
;
500 plugin
->editor_watch_id
= 0;
502 plugin
->assist
= NULL
;
503 plugin
->settings
= g_settings_new (PREF_SCHEMA
);
507 python_plugin_class_init (GObjectClass
*klass
)
509 AnjutaPluginClass
*plugin_class
= ANJUTA_PLUGIN_CLASS (klass
);
511 parent_class
= g_type_class_peek_parent (klass
);
513 plugin_class
->activate
= python_plugin_activate
;
514 plugin_class
->deactivate
= python_plugin_deactivate
;
515 klass
->finalize
= python_plugin_finalize
;
516 klass
->dispose
= python_plugin_dispose
;
519 #define PREF_WIDGET_SPACE "preferences:completion-space-after-func"
520 #define PREF_WIDGET_BRACE "preferences:completion-brace-after-func"
521 #define PREF_WIDGET_CLOSEBRACE "preferences:completion-closebrace-after-func"
522 #define PREF_WIDGET_AUTO "preferences:completion-enable"
525 on_autocompletion_toggled (GtkToggleButton
* button
,
526 PythonPlugin
* plugin
)
529 gboolean sensitive
= gtk_toggle_button_get_active (button
);
531 widget
= GTK_WIDGET (gtk_builder_get_object (plugin
->bxml
, PREF_WIDGET_SPACE
));
532 gtk_widget_set_sensitive (widget
, sensitive
);
533 widget
= GTK_WIDGET (gtk_builder_get_object (plugin
->bxml
, PREF_WIDGET_BRACE
));
534 gtk_widget_set_sensitive (widget
, sensitive
);
535 widget
= GTK_WIDGET (gtk_builder_get_object (plugin
->bxml
, PREF_WIDGET_CLOSEBRACE
));
536 gtk_widget_set_sensitive (widget
, sensitive
);
540 ipreferences_merge (IAnjutaPreferences
* ipref
, AnjutaPreferences
* prefs
,
543 /* Add preferences */
544 GError
* error
= NULL
;
545 PythonPlugin
* plugin
= ANJUTA_PLUGIN_PYTHON (ipref
);
546 plugin
->bxml
= gtk_builder_new ();
549 if (!gtk_builder_add_from_file (plugin
->bxml
, PROPERTIES_FILE_UI
, &error
))
551 g_warning ("Couldn't load builder file: %s", error
->message
);
552 g_error_free (error
);
554 anjuta_preferences_add_from_builder (prefs
,
557 "preferences", _("Python"),
559 toggle
= GTK_WIDGET (gtk_builder_get_object (plugin
->bxml
, PREF_WIDGET_AUTO
));
560 g_signal_connect (toggle
, "toggled", G_CALLBACK (on_autocompletion_toggled
),
562 on_autocompletion_toggled (GTK_TOGGLE_BUTTON (toggle
), plugin
);
566 ipreferences_unmerge (IAnjutaPreferences
* ipref
, AnjutaPreferences
* prefs
,
569 PythonPlugin
* plugin
= ANJUTA_PLUGIN_PYTHON (ipref
);
570 anjuta_preferences_remove_page(prefs
, _("Python"));
571 g_object_unref (plugin
->bxml
);
575 ipreferences_iface_init (IAnjutaPreferencesIface
* iface
)
577 iface
->merge
= ipreferences_merge
;
578 iface
->unmerge
= ipreferences_unmerge
;
581 ANJUTA_PLUGIN_BEGIN (PythonPlugin
, python_plugin
);
582 ANJUTA_PLUGIN_ADD_INTERFACE(ipreferences
, IANJUTA_TYPE_PREFERENCES
);
585 ANJUTA_SIMPLE_PLUGIN (PythonPlugin
, python_plugin
);