1 /*
2  *  geanyprj - Alternative project support for geany light IDE.
3  *
4  *  Copyright 2007 Frank Lanitz <frank(at)frank(dot)uvena(dot)de>
5  *  Copyright 2007 Enrico Tröger <enrico.troeger@uvena.de>
6  *  Copyright 2007 Nick Treleaven <nick.treleaven@btinternet.com>
7  *  Copyright 2007, 2008 Yura Siamashka <yurand2@gmail.com>
8  *
9  *  This program is free software: you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation, either version 3 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #ifdef HAVE_LOCALE_H
24 # include <locale.h>
25 #endif
26 
27 #ifdef HAVE_CONFIG_H
28 	#include "config.h" /* for the gettext domain */
29 #endif
30 #include <geanyplugin.h>
31 
32 #include <sys/time.h>
33 #include <string.h>
34 
35 #include "geanyprj.h"
36 
37 PLUGIN_VERSION_CHECK(224)
38 PLUGIN_SET_TRANSLATABLE_INFO(LOCALEDIR, GETTEXT_PACKAGE,
39 	"GeanyPrj", _("Alternative project support. \nThis plugin currently "
40 		          "has no maintainer. Would you like to help by contributing "
41 		          "to this plugin?"),
42 	VERSION,
43 	"Yura Siamashka <yurand2@gmail.com>")
44 
45 GeanyPlugin    *geany_plugin;
46 GeanyData      *geany_data;
47 
48 
49 static gchar    *config_file;
50 static gboolean  display_sidebar = TRUE;
51 
52 
53 /* Keybinding(s) */
54 enum
55 {
56 	KB_FIND_IN_PROJECT,
57 	KB_COUNT
58 };
59 
60 
reload_project(void)61 static void reload_project(void)
62 {
63 	gchar *dir;
64 	gchar *proj;
65 	GeanyDocument *doc;
66 
67 	debug("%s\n", __FUNCTION__);
68 
69 	doc = document_get_current();
70 	if (doc == NULL || doc->file_name == NULL)
71 		return;
72 
73 	dir = g_path_get_dirname(doc->file_name);
74 	proj = find_file_path(dir, ".geanyprj");
75 
76 	if (!proj)
77 	{
78 		if (g_current_project)
79 			xproject_close(TRUE);
80 		return;
81 	}
82 
83 	if (!g_current_project)
84 	{
85 		xproject_open(proj);
86 	}
87 	else if (strcmp(proj, g_current_project->path) != 0)
88 	{
89 		xproject_close(TRUE);
90 		xproject_open(proj);
91 	}
92 	if (proj)
93 		g_free(proj);
94 }
95 
96 
on_doc_save(G_GNUC_UNUSED GObject * obj,GeanyDocument * doc,G_GNUC_UNUSED gpointer user_data)97 static void on_doc_save(G_GNUC_UNUSED GObject *obj, GeanyDocument *doc, G_GNUC_UNUSED gpointer user_data)
98 {
99 	gchar *name;
100 
101 	g_return_if_fail(doc != NULL && doc->file_name != NULL);
102 
103 	name = g_path_get_basename(doc->file_name);
104 	if (g_current_project && strcmp(name, ".geanyprj") == 0)
105 	{
106 		xproject_close(FALSE);
107 	}
108 	reload_project();
109 	xproject_update_tag(doc->file_name);
110 }
111 
112 
on_doc_open(G_GNUC_UNUSED GObject * obj,G_GNUC_UNUSED GeanyDocument * doc,G_GNUC_UNUSED gpointer user_data)113 static void on_doc_open(G_GNUC_UNUSED GObject *obj, G_GNUC_UNUSED GeanyDocument *doc,
114 						G_GNUC_UNUSED gpointer user_data)
115 {
116 	reload_project();
117 }
118 
119 
on_doc_activate(G_GNUC_UNUSED GObject * obj,G_GNUC_UNUSED GeanyDocument * doc,G_GNUC_UNUSED gpointer user_data)120 static void on_doc_activate(G_GNUC_UNUSED GObject *obj, G_GNUC_UNUSED GeanyDocument *doc,
121 							G_GNUC_UNUSED gpointer user_data)
122 {
123 	reload_project();
124 }
125 
126 
127 PluginCallback plugin_callbacks[] = {
128 	{"document-open", (GCallback) & on_doc_open, TRUE, NULL},
129 	{"document-save", (GCallback) & on_doc_save, TRUE, NULL},
130 	{"document-activate", (GCallback) & on_doc_activate, TRUE, NULL},
131 	{NULL, NULL, FALSE, NULL}
132 };
133 
134 
135 /* Keybinding callback */
kb_find_in_project(guint key_id)136 static void kb_find_in_project(guint key_id)
137 {
138 	on_find_in_project(NULL, NULL);
139 }
140 
141 
load_settings(void)142 static void load_settings(void)
143 {
144 	GKeyFile *config = g_key_file_new();
145 	GError   *err    = NULL;
146 	gboolean  tmp;
147 
148 	config_file = g_strconcat(geany->app->configdir, G_DIR_SEPARATOR_S, "plugins", G_DIR_SEPARATOR_S,
149 		"geanyprj", G_DIR_SEPARATOR_S, "geanyprj.conf", NULL);
150 	g_key_file_load_from_file(config, config_file, G_KEY_FILE_NONE, NULL);
151 
152 	tmp = g_key_file_get_boolean(config, "geanyprj", "display_sidebar", &err);
153 
154 	if (err)
155 		g_error_free(err);
156 	else
157 		display_sidebar = tmp;
158 
159 	g_key_file_free(config);
160 }
161 
162 
save_settings(void)163 static void save_settings(void)
164 {
165 	GKeyFile *config = g_key_file_new();
166 	gchar    *data;
167 	gchar    *config_dir = g_path_get_dirname(config_file);
168 
169 	g_key_file_load_from_file(config, config_file, G_KEY_FILE_NONE, NULL);
170 
171 	g_key_file_set_boolean(config, "geanyprj", "display_sidebar", display_sidebar);
172 
173 	if (! g_file_test(config_dir, G_FILE_TEST_IS_DIR) && utils_mkdir(config_dir, TRUE) != 0)
174 	{
175 		dialogs_show_msgbox(GTK_MESSAGE_ERROR,
176 			_("Plugin configuration directory could not be created."));
177 	}
178 	else
179 	{
180 		/* write config to file */
181 		data = g_key_file_to_data(config, NULL, NULL);
182 		utils_write_file(config_file, data);
183 		g_free(data);
184 	}
185 	g_free(config_dir);
186 	g_key_file_free(config);
187 }
188 
189 
on_configure_response(G_GNUC_UNUSED GtkDialog * dialog,G_GNUC_UNUSED gint response,GtkWidget * checkbox)190 static void on_configure_response(G_GNUC_UNUSED GtkDialog *dialog, G_GNUC_UNUSED gint response, GtkWidget *checkbox)
191 {
192 	gboolean old_display_sidebar = display_sidebar;
193 
194 	display_sidebar = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbox));
195 
196 	if (display_sidebar ^ old_display_sidebar)
197 	{
198 		if (display_sidebar)
199 		{
200 			create_sidebar();
201 			sidebar_refresh();
202 		}
203 		else
204 		{
205 			destroy_sidebar();
206 		}
207 		save_settings();
208 	}
209 }
210 
211 
212 /* Called by Geany to initialize the plugin */
plugin_init(G_GNUC_UNUSED GeanyData * data)213 void plugin_init(G_GNUC_UNUSED GeanyData *data)
214 {
215 	GeanyKeyGroup *key_group;
216 
217 	load_settings();
218 	tools_menu_init();
219 
220 	xproject_init();
221 	if (display_sidebar)
222 		create_sidebar();
223 	reload_project();
224 
225 	key_group = plugin_set_key_group(geany_plugin, "geanyprj", KB_COUNT, NULL);
226 	keybindings_set_item(key_group, KB_FIND_IN_PROJECT,
227 		kb_find_in_project, 0, 0, "find_in_project",
228 			_("Find a text in geanyprj's project"), NULL);
229 }
230 
231 
232 /* Called by Geany to show the plugin's configure dialog. This function is always called after
233  * plugin_init() was called.
234  */
plugin_configure(GtkDialog * dialog)235 GtkWidget *plugin_configure(GtkDialog *dialog)
236 {
237 	GtkWidget *vbox;
238 	GtkWidget *checkbox;
239 
240 	vbox = gtk_vbox_new(FALSE, 6);
241 
242 	checkbox = gtk_check_button_new_with_label(_("Display sidebar"));
243 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbox), display_sidebar);
244 
245 	gtk_box_pack_start(GTK_BOX(vbox), checkbox, FALSE, FALSE, 0);
246 
247 	gtk_widget_show_all(vbox);
248 
249 	/* Connect a callback for when the user clicks a dialog button */
250 	g_signal_connect(dialog, "response", G_CALLBACK(on_configure_response), checkbox);
251 
252 	return vbox;
253 }
254 
255 
256 /* Called by Geany before unloading the plugin. */
plugin_cleanup(void)257 void plugin_cleanup(void)
258 {
259 	tools_menu_uninit();
260 
261 	if (g_current_project)
262 		geany_project_free(g_current_project);
263 	g_current_project = NULL;
264 
265 	g_free(config_file);
266 
267 	xproject_cleanup();
268 	destroy_sidebar();
269 }
270