1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3  * plugin.c
4  * Copyright (C) Ishan Chattopadhyaya 2009 <ichattopadhyaya@gmail.com>
5  *
6  * plugin.c is free software.
7  *
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)
11  * any later version.
12  *
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.
17  *
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.
23  */
24 
25 #include <config.h>
26 #include <ctype.h>
27 #include <stdlib.h>
28 #include <libanjuta/anjuta-shell.h>
29 #include <libanjuta/anjuta-debug.h>
30 #include <libanjuta/interfaces/ianjuta-iterable.h>
31 #include <libanjuta/interfaces/ianjuta-document.h>
32 #include <libanjuta/interfaces/ianjuta-document-manager.h>
33 #include <libanjuta/interfaces/ianjuta-editor.h>
34 #include <libanjuta/interfaces/ianjuta-file.h>
35 #include <libanjuta/interfaces/ianjuta-editor-cell.h>
36 #include <libanjuta/interfaces/ianjuta-editor-language.h>
37 #include <libanjuta/interfaces/ianjuta-editor-selection.h>
38 #include <libanjuta/interfaces/ianjuta-preferences.h>
39 #include <libanjuta/interfaces/ianjuta-language.h>
40 #include <libanjuta/interfaces/ianjuta-indenter.h>
41 
42 #include "plugin.h"
43 #include "python-indentation.h"
44 
45 /* Pixmaps */
46 #define ANJUTA_STOCK_AUTOINDENT           "anjuta-indent"
47 
48 #define UI_FILE PACKAGE_DATA_DIR"/ui/anjuta-indentation-python-style.xml"
49 #define PROPERTIES_FILE_UI PACKAGE_DATA_DIR"/glade/anjuta-indentation-python-style.ui"
50 #define ICON_FILE "anjuta-indentation-python-style-plugin.png"
51 
52 /* Preferences keys */
53 #define ANJUTA_PREF_SCHEMA_PREFIX "org.gnome.anjuta."
54 #define PREF_SCHEMA "org.gnome.anjuta.plugins.indent-python"
55 
56 static gpointer parent_class;
57 
58 static void
on_editor_char_inserted_python(IAnjutaEditor * editor,IAnjutaIterable * insert_pos,gchar ch,IndentPythonPlugin * plugin)59 on_editor_char_inserted_python (IAnjutaEditor *editor,
60                                 IAnjutaIterable *insert_pos,
61                                 gchar ch,
62                                 IndentPythonPlugin *plugin)
63 {
64 	python_indent (plugin, editor, insert_pos, ch);
65 }
66 
67 static void
install_support(IndentPythonPlugin * lang_plugin)68 install_support (IndentPythonPlugin *lang_plugin)
69 {
70 	IAnjutaLanguage* lang_manager =
71 		anjuta_shell_get_interface (ANJUTA_PLUGIN (lang_plugin)->shell,
72 									IAnjutaLanguage, NULL);
73 
74 	if (!lang_manager)
75 		return;
76 
77 	if (lang_plugin->support_installed)
78 		return;
79 
80 	lang_plugin->current_language =
81 		ianjuta_language_get_name_from_editor (lang_manager,
82 											   IANJUTA_EDITOR_LANGUAGE (lang_plugin->current_editor), NULL);
83 
84 	if (lang_plugin->current_language &&
85 		(g_str_equal (lang_plugin->current_language, "Python")))
86 	{
87 		g_signal_connect (lang_plugin->current_editor,
88 							"char-added",
89 							G_CALLBACK (on_editor_char_inserted_python),
90 							lang_plugin);
91 	}
92 	else
93 	{
94 		return;
95 	}
96 
97 	python_indent_init (lang_plugin);
98 	/* Disable editor intern auto-indent */
99 	ianjuta_editor_set_auto_indent (IANJUTA_EDITOR(lang_plugin->current_editor),
100 								    FALSE, NULL);
101 
102 	lang_plugin->support_installed = TRUE;
103 }
104 
105 static void
uninstall_support(IndentPythonPlugin * lang_plugin)106 uninstall_support (IndentPythonPlugin *lang_plugin)
107 {
108 	if (!lang_plugin->support_installed)
109 		return;
110 
111 	if (lang_plugin->current_language &&
112 		(g_str_equal (lang_plugin->current_language, "Python")))
113 	{
114 		g_signal_handlers_disconnect_by_func (lang_plugin->current_editor,
115 									G_CALLBACK (on_editor_char_inserted_python),
116 									lang_plugin);
117 	}
118 
119 	lang_plugin->support_installed = FALSE;
120 }
121 
122 static void
on_editor_language_changed(IAnjutaEditor * editor,const gchar * new_language,IndentPythonPlugin * plugin)123 on_editor_language_changed (IAnjutaEditor *editor,
124 							const gchar *new_language,
125 							IndentPythonPlugin *plugin)
126 {
127 	uninstall_support (plugin);
128 	install_support (plugin);
129 }
130 
131 static void
on_editor_added(AnjutaPlugin * plugin,const gchar * name,const GValue * value,gpointer data)132 on_editor_added (AnjutaPlugin *plugin, const gchar *name,
133                  const GValue *value, gpointer data)
134 {
135 	IndentPythonPlugin *lang_plugin;
136 	IAnjutaDocument* doc = IANJUTA_DOCUMENT(g_value_get_object (value));
137 	lang_plugin = ANJUTA_PLUGIN_INDENT_PYTHON(plugin);
138 
139 
140 	if (IANJUTA_IS_EDITOR(doc))
141 	{
142 		lang_plugin->current_editor = G_OBJECT(doc);
143 	}
144 	else
145 	{
146 		lang_plugin->current_editor = NULL;
147 		return;
148 	}
149 	if (lang_plugin->current_editor)
150 	{
151 		IAnjutaEditor* editor = IANJUTA_EDITOR (lang_plugin->current_editor);
152 		GFile* current_editor_file = ianjuta_file_get_file (IANJUTA_FILE (editor),
153 		                                                    NULL);
154 
155 		if (current_editor_file)
156 		{
157 			lang_plugin->current_editor_filename = g_file_get_path (current_editor_file);
158 			g_object_unref (current_editor_file);
159 		}
160 
161 		install_support (lang_plugin);
162 		g_signal_connect (lang_plugin->current_editor, "language-changed",
163 		                  G_CALLBACK (on_editor_language_changed),
164 		                  plugin);
165 	}
166 }
167 
168 static void
on_editor_removed(AnjutaPlugin * plugin,const gchar * name,gpointer data)169 on_editor_removed (AnjutaPlugin *plugin, const gchar *name,
170                  gpointer data)
171 {
172 	IndentPythonPlugin *lang_plugin;
173 	lang_plugin = ANJUTA_PLUGIN_INDENT_PYTHON (plugin);
174 
175 	if (lang_plugin->current_editor)
176 		g_signal_handlers_disconnect_by_func (lang_plugin->current_editor,
177 										  G_CALLBACK (on_editor_language_changed),
178 										  plugin);
179 
180 	uninstall_support (lang_plugin);
181 
182 
183 	g_free (lang_plugin->current_editor_filename);
184 	lang_plugin->current_editor_filename = NULL;
185 	lang_plugin->current_editor = NULL;
186 	lang_plugin->current_language = NULL;
187 }
188 
189 static void
on_auto_indent(GtkAction * action,gpointer data)190 on_auto_indent (GtkAction *action, gpointer data)
191 {
192 	IndentPythonPlugin *lang_plugin = ANJUTA_PLUGIN_INDENT_PYTHON (data);
193 
194 	python_indent_auto (lang_plugin, NULL, NULL);
195 }
196 
197 static GtkActionEntry actions[] = {
198 	{
199 		"ActionMenuEdit",
200 		NULL, N_("_Edit"),
201 		NULL, NULL, NULL
202 	},
203 	{
204 		"ActionEditAutoindent",
205 		GTK_STOCK_NEW, //ANJUTA_STOCK_AUTOINDENT,
206 		N_("Auto-Indent"), "<control>i",
207 		N_("Auto-indent current line or selection based on indentation settings"),
208 		G_CALLBACK (on_auto_indent)
209 	}
210 };
211 
212 static gboolean
indent_python_plugin_activate(AnjutaPlugin * plugin)213 indent_python_plugin_activate (AnjutaPlugin *plugin)
214 {
215 	AnjutaUI *ui;
216 
217 	IndentPythonPlugin *python_plugin;
218 	python_plugin = (IndentPythonPlugin*) plugin;
219 
220 	python_plugin->prefs = anjuta_shell_get_preferences (plugin->shell, NULL);
221 
222 	/* Add all UI actions and merge UI */
223 	ui = anjuta_shell_get_ui (plugin->shell, NULL);
224 
225 	python_plugin->action_group =
226 		anjuta_ui_add_action_group_entries (ui, "ActionGroupPythonIndent",
227 											_("Python Indentation"),
228 											actions,
229 											G_N_ELEMENTS (actions),
230 											GETTEXT_PACKAGE, TRUE,
231 											plugin);
232 	python_plugin->uiid = anjuta_ui_merge (ui, UI_FILE);
233 
234 	/* Add watches */
235 	python_plugin->editor_watch_id = anjuta_plugin_add_watch (plugin,
236 														IANJUTA_DOCUMENT_MANAGER_CURRENT_DOCUMENT,
237 														on_editor_added,
238 														on_editor_removed,
239 														NULL);
240 	return TRUE;
241 }
242 
243 static gboolean
indent_python_plugin_deactivate(AnjutaPlugin * plugin)244 indent_python_plugin_deactivate (AnjutaPlugin *plugin)
245 {
246 
247 	AnjutaUI *ui;
248 	IndentPythonPlugin *lang_plugin;
249 	lang_plugin = (IndentPythonPlugin*) (plugin);
250 
251 	anjuta_plugin_remove_watch (plugin,
252 								lang_plugin->editor_watch_id,
253 								TRUE);
254 
255 	ui = anjuta_shell_get_ui (plugin->shell, NULL);
256 	anjuta_ui_remove_action_group (ui, ANJUTA_PLUGIN_INDENT_PYTHON(plugin)->action_group);
257 	anjuta_ui_unmerge (ui, ANJUTA_PLUGIN_INDENT_PYTHON(plugin)->uiid);
258 
259 	return TRUE;
260 }
261 
262 static void
indent_python_plugin_finalize(GObject * obj)263 indent_python_plugin_finalize (GObject *obj)
264 {
265 	/* Finalization codes here */
266 	G_OBJECT_CLASS (parent_class)->finalize (obj);
267 }
268 
269 static void
indent_python_plugin_dispose(GObject * obj)270 indent_python_plugin_dispose (GObject *obj)
271 {
272 	/* Disposition codes */
273 	IndentPythonPlugin *plugin = (IndentPythonPlugin*)obj;
274 
275 	if (plugin->settings)
276 		g_object_unref (plugin->settings);
277 	plugin->settings = NULL;
278 
279 	G_OBJECT_CLASS (parent_class)->dispose (obj);
280 }
281 
282 static void
indent_python_plugin_instance_init(GObject * obj)283 indent_python_plugin_instance_init (GObject *obj)
284 {
285 	IndentPythonPlugin *plugin = (IndentPythonPlugin*)obj;
286 	plugin->action_group = NULL;
287 	plugin->current_editor = NULL;
288 	plugin->current_language = NULL;
289 	plugin->editor_watch_id = 0;
290 	plugin->uiid = 0;
291 	plugin->settings = g_settings_new (PREF_SCHEMA);
292 }
293 
294 static void
indent_python_plugin_class_init(GObjectClass * klass)295 indent_python_plugin_class_init (GObjectClass *klass)
296 {
297 	AnjutaPluginClass *plugin_class = ANJUTA_PLUGIN_CLASS (klass);
298 
299 	parent_class = g_type_class_peek_parent (klass);
300 
301 	plugin_class->activate = indent_python_plugin_activate;
302 	plugin_class->deactivate = indent_python_plugin_deactivate;
303 	klass->finalize = indent_python_plugin_finalize;
304 	klass->dispose = indent_python_plugin_dispose;
305 }
306 
307 
308 static void
ipreferences_merge(IAnjutaPreferences * ipref,AnjutaPreferences * prefs,GError ** e)309 ipreferences_merge (IAnjutaPreferences* ipref, AnjutaPreferences* prefs,
310 					GError** e)
311 {
312 	GError* error = NULL;
313 	IndentPythonPlugin* plugin = ANJUTA_PLUGIN_INDENT_PYTHON (ipref);
314 	plugin->bxml = gtk_builder_new ();
315 
316 	/* Add preferences */
317     if (!gtk_builder_add_from_file (plugin->bxml, PROPERTIES_FILE_UI, &error))
318     {
319         g_warning ("Couldn't load builder file: %s", error->message);
320         g_error_free (error);
321     }
322 	anjuta_preferences_add_from_builder (prefs,
323 	                                     plugin->bxml, plugin->settings,
324 	                                     "preferences", _("Indentation"),
325 	                                     ICON_FILE);
326 }
327 
328 static void
ipreferences_unmerge(IAnjutaPreferences * ipref,AnjutaPreferences * prefs,GError ** e)329 ipreferences_unmerge (IAnjutaPreferences* ipref, AnjutaPreferences* prefs,
330 					  GError** e)
331 {
332 	IndentPythonPlugin* plugin = ANJUTA_PLUGIN_INDENT_PYTHON (ipref);
333 	anjuta_preferences_remove_page(prefs, _("Indentation"));
334 	g_object_unref (plugin->bxml);
335 }
336 
337 static void
ipreferences_iface_init(IAnjutaPreferencesIface * iface)338 ipreferences_iface_init (IAnjutaPreferencesIface* iface)
339 {
340 	iface->merge = ipreferences_merge;
341 	iface->unmerge = ipreferences_unmerge;
342 }
343 
344 static void
iindenter_indent(IAnjutaIndenter * indenter,IAnjutaIterable * start,IAnjutaIterable * end,GError ** e)345 iindenter_indent (IAnjutaIndenter* indenter,
346                   IAnjutaIterable* start,
347                   IAnjutaIterable* end,
348                   GError** e)
349 {
350 	IndentPythonPlugin* plugin = ANJUTA_PLUGIN_INDENT_PYTHON (indenter);
351 
352 	python_indent_auto (plugin,
353 	                    start, end);
354 }
355 
356 static void
iindenter_iface_init(IAnjutaIndenterIface * iface)357 iindenter_iface_init (IAnjutaIndenterIface* iface)
358 {
359 	iface->indent = iindenter_indent;
360 }
361 
362 ANJUTA_PLUGIN_BEGIN (IndentPythonPlugin, indent_python_plugin);
363 ANJUTA_PLUGIN_ADD_INTERFACE(ipreferences, IANJUTA_TYPE_PREFERENCES);
364 ANJUTA_PLUGIN_ADD_INTERFACE(iindenter, IANJUTA_TYPE_INDENTER);
365 ANJUTA_PLUGIN_END;
366 
367 ANJUTA_SIMPLE_PLUGIN (IndentPythonPlugin, indent_python_plugin);
368