1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3  * anjuta
4  * Copyright (C) James Liggett 2007 <jrliggett@cox.net>
5  *
6  * Portions based on the original Subversion plugin
7  * Copyright (C) Johannes Schmid 2005
8  *
9  * anjuta is free software.
10  *
11  * You may redistribute it and/or modify it under the terms of the
12  * GNU General Public License, as published by the Free Software
13  * Foundation; either version 2 of the License, or (at your option)
14  * any later version.
15  *
16  * anjuta is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19  * See the GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with anjuta.  If not, write to:
23  * 	The Free Software Foundation, Inc.,
24  * 	51 Franklin Street, Fifth Floor
25  * 	Boston, MA  02110-1301, USA.
26  */
27 
28 #include "subversion-ui-utils.h"
29 
30 /* Private structure for pulse progress */
31 typedef struct
32 {
33 	AnjutaStatus *status;
34 	gchar *text;
35 } PulseProgressData;
36 
37 SubversionData*
subversion_data_new(Subversion * plugin,GtkBuilder * bxml)38 subversion_data_new (Subversion* plugin, GtkBuilder* bxml)
39 {
40 	SubversionData* data = g_new0(SubversionData, 1);
41 	data->plugin = plugin;
42 	data->bxml = bxml;
43 
44 	return data;
45 }
46 
subversion_data_free(SubversionData * data)47 void subversion_data_free(SubversionData* data)
48 {
49 	g_free(data);
50 }
51 
52 static void
on_mesg_view_destroy(Subversion * plugin,gpointer destroyed_view)53 on_mesg_view_destroy(Subversion* plugin, gpointer destroyed_view)
54 {
55 	plugin->mesg_view = NULL;
56 }
57 
58 void
create_message_view(Subversion * plugin)59 create_message_view(Subversion* plugin)
60 {
61 	IAnjutaMessageManager* mesg_manager = anjuta_shell_get_interface
62 		(ANJUTA_PLUGIN (plugin)->shell,	IAnjutaMessageManager, NULL);
63 	plugin->mesg_view =
64 	    ianjuta_message_manager_get_view_by_name(mesg_manager, _("Subversion"),
65 												 NULL);
66 	if (!plugin->mesg_view)
67 	{
68 		plugin->mesg_view =
69 		     ianjuta_message_manager_add_view (mesg_manager, _("Subversion"),
70 											   ICON_FILE, NULL);
71 		g_object_weak_ref (G_OBJECT (plugin->mesg_view),
72 						  (GWeakNotify)on_mesg_view_destroy, plugin);
73 	}
74 	ianjuta_message_view_clear(plugin->mesg_view, NULL);
75 	ianjuta_message_manager_set_current_view(mesg_manager, plugin->mesg_view,
76 											 NULL);
77 }
78 
79 gboolean
check_input(GtkWidget * parent,GtkWidget * entry,const gchar * error_message)80 check_input (GtkWidget *parent, GtkWidget *entry, const gchar *error_message)
81 {
82 	gchar *input;
83 	gboolean ret;
84 	GtkWidget *dialog;
85 
86 	input = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
87 
88 	if (strlen (input) > 0)
89 		ret = TRUE;
90 	else
91 	{
92 		dialog = gtk_message_dialog_new (GTK_WINDOW (parent),
93 										 GTK_DIALOG_DESTROY_WITH_PARENT,
94 										 GTK_MESSAGE_WARNING,
95 										 GTK_BUTTONS_OK,
96 										 "%s", error_message);
97 
98 		gtk_dialog_run (GTK_DIALOG (dialog));
99 		gtk_widget_destroy (dialog);
100 
101 		gtk_window_set_focus (GTK_WINDOW (parent), entry);
102 
103 		ret = FALSE;
104 	}
105 
106 	g_free (input);
107 
108 	return ret;
109 }
110 
111 gchar *
get_log_from_textview(GtkWidget * textview)112 get_log_from_textview (GtkWidget* textview)
113 {
114 	gchar* log;
115 	GtkTextBuffer* textbuf;
116 	GtkTextIter iterbegin, iterend;
117 
118 	textbuf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
119 	gtk_text_buffer_get_start_iter (textbuf, &iterbegin);
120 	gtk_text_buffer_get_end_iter (textbuf, &iterend);
121 	log = gtk_text_buffer_get_text (textbuf, &iterbegin, &iterend, FALSE);
122 
123 	return log;
124 }
125 
126 static gboolean
status_pulse_timer(PulseProgressData * data)127 status_pulse_timer (PulseProgressData *data)
128 {
129 	anjuta_status_progress_pulse (data->status, data->text);
130 	return TRUE;
131 }
132 
133 static gboolean
pulse_timer(GtkProgressBar * progress_bar)134 pulse_timer (GtkProgressBar *progress_bar)
135 {
136 	gtk_progress_bar_pulse (progress_bar);
137 	return TRUE;
138 }
139 
140 static void
on_pulse_timer_destroyed(PulseProgressData * data)141 on_pulse_timer_destroyed (PulseProgressData *data)
142 {
143 	anjuta_status_progress_reset (data->status);
144 
145 	g_free (data->text);
146 	g_free (data);
147 }
148 
149 guint
status_bar_progress_pulse(Subversion * plugin,gchar * text)150 status_bar_progress_pulse (Subversion *plugin, gchar *text)
151 {
152 	PulseProgressData *data;
153 
154 	data = g_new0 (PulseProgressData, 1);
155 	data->status = anjuta_shell_get_status (ANJUTA_PLUGIN (plugin)->shell,
156 											NULL);
157 	data->text = g_strdup (text);
158 
159 	return g_timeout_add_full (G_PRIORITY_DEFAULT, 100,
160 							   (GSourceFunc) status_pulse_timer, data,
161 							   (GDestroyNotify) on_pulse_timer_destroyed);
162 }
163 
164 void
clear_status_bar_progress_pulse(guint timer_id)165 clear_status_bar_progress_pulse (guint timer_id)
166 {
167 	g_source_remove (timer_id);
168 }
169 
170 void
report_errors(AnjutaCommand * command,guint return_code)171 report_errors (AnjutaCommand *command, guint return_code)
172 {
173 	gchar *message;
174 
175 	if (return_code != 0)
176 	{
177 		message = anjuta_command_get_error_message (command);
178 
179 		anjuta_util_dialog_error (NULL, message);
180 		g_free (message);
181 	}
182 }
183 
184 static void
stop_pulse_timer(gpointer timer_id,GtkProgressBar * progress_bar)185 stop_pulse_timer (gpointer timer_id, GtkProgressBar *progress_bar)
186 {
187 	g_source_remove (GPOINTER_TO_UINT (timer_id));
188 }
189 
190 void
pulse_progress_bar(GtkProgressBar * progress_bar)191 pulse_progress_bar (GtkProgressBar *progress_bar)
192 {
193 	guint timer_id;
194 
195 	timer_id = g_timeout_add (100, (GSourceFunc) pulse_timer,
196 							  progress_bar);
197 	g_object_set_data (G_OBJECT (progress_bar), "pulse-timer-id",
198 					   GUINT_TO_POINTER (timer_id));
199 
200 	g_object_weak_ref (G_OBJECT (progress_bar),
201 					   (GWeakNotify) stop_pulse_timer,
202 					   GUINT_TO_POINTER (timer_id));
203 }
204 
205 gchar *
get_filename_from_full_path(gchar * path)206 get_filename_from_full_path (gchar *path)
207 {
208 	gchar *last_slash;
209 
210 	last_slash = strrchr (path, '/');
211 
212 	/* There might be a trailing slash in the string */
213 	if ((last_slash - path) < strlen (path))
214 		return g_strdup (last_slash + 1);
215 	else
216 		return g_strdup ("");
217 }
218 
219 void
on_status_command_finished(AnjutaCommand * command,guint return_code,gpointer user_data)220 on_status_command_finished (AnjutaCommand *command, guint return_code,
221 							gpointer user_data)
222 {
223 	report_errors (command, return_code);
224 
225 	svn_status_command_destroy (SVN_STATUS_COMMAND (command));
226 }
227 
228 void
on_status_command_data_arrived(AnjutaCommand * command,AnjutaVcsStatusTreeView * tree_view)229 on_status_command_data_arrived (AnjutaCommand *command,
230 								AnjutaVcsStatusTreeView *tree_view)
231 {
232 	GQueue *status_queue;
233 	SvnStatus *status;
234 	gchar *path;
235 
236 	status_queue = svn_status_command_get_status_queue (SVN_STATUS_COMMAND (command));
237 
238 	while (g_queue_peek_head (status_queue))
239 	{
240 		status = g_queue_pop_head (status_queue);
241 		path = svn_status_get_path (status);
242 
243 		anjuta_vcs_status_tree_view_add (tree_view, path,
244 								  svn_status_get_vcs_status (status),
245 								  FALSE);
246 
247 		svn_status_destroy (status);
248 		g_free (path);
249 	}
250 }
251 
252 void
on_command_info_arrived(AnjutaCommand * command,Subversion * plugin)253 on_command_info_arrived (AnjutaCommand *command, Subversion *plugin)
254 {
255 	GQueue *info;
256 	gchar *message;
257 
258 	info = svn_command_get_info_queue (SVN_COMMAND (command));
259 
260 	while (g_queue_peek_head (info))
261 	{
262 		message = g_queue_pop_head (info);
263 		ianjuta_message_view_append (plugin->mesg_view,
264 								     IANJUTA_MESSAGE_VIEW_TYPE_INFO,
265 									 message, "", NULL);
266 		g_free (message);
267 	}
268 }
269 
270 void
select_all_status_items(GtkButton * select_all_button,AnjutaVcsStatusTreeView * tree_view)271 select_all_status_items (GtkButton *select_all_button,
272 						 AnjutaVcsStatusTreeView *tree_view)
273 {
274 	anjuta_vcs_status_tree_view_select_all (tree_view);
275 }
276 
277 void
clear_all_status_selections(GtkButton * clear_button,AnjutaVcsStatusTreeView * tree_view)278 clear_all_status_selections (GtkButton *clear_button,
279 							 AnjutaVcsStatusTreeView *tree_view)
280 {
281 	anjuta_vcs_status_tree_view_unselect_all (tree_view);
282 }
283 
284 void
init_whole_project(Subversion * plugin,GtkWidget * project,gboolean active)285 init_whole_project (Subversion *plugin, GtkWidget* project, gboolean active)
286 {
287 	gboolean project_loaded;
288 
289 	project_loaded = (plugin->project_root_dir != NULL);
290 
291 	gtk_widget_set_sensitive(project, project_loaded);
292 
293 	if (project_loaded)
294 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (project), active);
295 }
296 
297 void
on_whole_project_toggled(GtkToggleButton * project,Subversion * plugin)298 on_whole_project_toggled (GtkToggleButton* project, Subversion *plugin)
299 {
300 	GtkEntry* fileentry;
301 
302 	fileentry = g_object_get_data (G_OBJECT (project), "fileentry");
303 
304 	if (gtk_toggle_button_get_active(project) && plugin->project_root_dir)
305 	{
306 		gtk_entry_set_text (fileentry, plugin->project_root_dir);
307 		gtk_widget_set_sensitive(GTK_WIDGET(fileentry), FALSE);
308 	}
309 	else
310 		gtk_widget_set_sensitive(GTK_WIDGET(fileentry), TRUE);
311 }
312 
313 void
send_diff_command_output_to_editor(AnjutaCommand * command,IAnjutaEditor * editor)314 send_diff_command_output_to_editor (AnjutaCommand *command,
315 									IAnjutaEditor *editor)
316 {
317 	GQueue *output;
318 	gchar *line;
319 
320 	output = svn_diff_command_get_output (SVN_DIFF_COMMAND (command));
321 
322 	while (g_queue_peek_head (output))
323 	{
324 		line = g_queue_pop_head (output);
325 		ianjuta_editor_append (editor, line, strlen (line), NULL);
326 		g_free (line);
327 	}
328 }
329 
330 void
on_diff_command_finished(AnjutaCommand * command,guint return_code,Subversion * plugin)331 on_diff_command_finished (AnjutaCommand *command, guint return_code,
332 						  Subversion *plugin)
333 {
334 	AnjutaStatus *status;
335 
336 	status = anjuta_shell_get_status (ANJUTA_PLUGIN (plugin)->shell,
337 									  NULL);
338 
339 	anjuta_status (status, _("Subversion: Diff complete."), 5);
340 
341 	report_errors (command, return_code);
342 
343 	svn_diff_command_destroy (SVN_DIFF_COMMAND (command));
344 }
345 
346 void
stop_status_bar_progress_pulse(AnjutaCommand * command,guint return_code,gpointer timer_id)347 stop_status_bar_progress_pulse (AnjutaCommand *command, guint return_code,
348 								gpointer timer_id)
349 {
350 	clear_status_bar_progress_pulse (GPOINTER_TO_UINT (timer_id));
351 }
352 
353 void
hide_pulse_progress_bar(AnjutaCommand * command,guint return_code,GtkProgressBar * progress_bar)354 hide_pulse_progress_bar (AnjutaCommand *command, guint return_code,
355 						 GtkProgressBar *progress_bar)
356 {
357 	guint timer_id;
358 
359 	/* If the progress bar has already been destroyed, the timer should be
360 	 * stopped by stop_pulse_timer */
361 	if (GTK_IS_PROGRESS_BAR (progress_bar))
362 	{
363 		timer_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (progress_bar),
364 														"pulse-timer-id"));
365 
366 		g_source_remove (GPOINTER_TO_UINT (timer_id));
367 		gtk_widget_hide (GTK_WIDGET (progress_bar));
368 	}
369 }
370 
371 /* This function is normally intended to disconnect stock data-arrived signal
372  * handlers in this file. It is assumed that object is the user data for the
373  * callback. If you use any of the stock callbacks defined here, make sure
374  * to weak ref its target with this callback. Make sure to cancel this ref
375  * by connecting cancel_data_arrived_signal_disconnect to the command-finished
376  * signal so we don't try to disconnect signals on a destroyed command. */
377 void
disconnect_data_arrived_signals(AnjutaCommand * command,GObject * object)378 disconnect_data_arrived_signals (AnjutaCommand *command, GObject *object)
379 {
380 	guint data_arrived_signal;
381 
382 	if (ANJUTA_IS_COMMAND (command))
383 	{
384 		data_arrived_signal = g_signal_lookup ("data-arrived",
385 											   ANJUTA_TYPE_COMMAND);
386 
387 		g_signal_handlers_disconnect_matched (command,
388 											  G_SIGNAL_MATCH_DATA,
389 											  data_arrived_signal,
390 											  0,
391 											  NULL,
392 											  NULL,
393 											  object);
394 	}
395 
396 }
397 
398 void
cancel_data_arrived_signal_disconnect(AnjutaCommand * command,guint return_code,GObject * signal_target)399 cancel_data_arrived_signal_disconnect (AnjutaCommand *command,
400 									   guint return_code,
401 									   GObject *signal_target)
402 {
403 	g_object_weak_unref (signal_target,
404 						 (GWeakNotify) disconnect_data_arrived_signals,
405 						 command);
406 }
407 
408 void
on_subversion_browse_button_clicked(GtkButton * button,GtkEntry * entry)409 on_subversion_browse_button_clicked (GtkButton *button, GtkEntry *entry)
410 {
411 	GtkWidget *dialog;
412 	dialog = gtk_file_chooser_dialog_new ("Open File",
413 					      NULL,
414 					      GTK_FILE_CHOOSER_ACTION_OPEN,
415 					      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
416 					      GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
417 					      NULL);
418 	if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
419 	{
420 		char *filename;
421 		filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
422 
423 		gtk_entry_set_text (entry, filename);
424 
425 		g_free (filename);
426 	}
427 	gtk_widget_destroy (dialog);
428 }
429 
430