1 /*
2  * Bluefish HTML Editor
3  * bfwin_uimanager.c
4  *
5  * Copyright (C) 2011, 2015, 2017 James Hayward and Olivier Sessink
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 /*#define DEBUG*/
22 
23 #include <stdlib.h>				/* atoi */
24 
25 #include "config.h"
26 
27 #include "bfwin_uimanager.h"
28 #include "bfwin.h"
29 #include "bftextview2.h"
30 #include "bftextview2_langmgr.h"
31 #include "blocksync.h"
32 #include "bookmark.h"
33 #include "document.h"
34 #include "pixmap.h"
35 #include "doc_comments.h"
36 #include "doc_text_tools.h"
37 #include "doc_extern_tools.h"
38 #include "encodings_dialog.h"
39 #include "external_commands.h"
40 #include "file_dialogs.h"
41 #include "outputbox.h"
42 #include "preferences.h"
43 #include "project.h"
44 #include "stringlist.h"
45 #include "bf_lib.h"
46 #include "snr3.h"
47 #include "undo_redo.h"
48 #include "print.h"
49 
50 #define MAIN_MENU_UI PKGDATADIR"/ui/bluefish_menu_ui.xml"
51 #define MAIN_TOOLBAR_UI PKGDATADIR"/ui/bluefish_toolbar_ui.xml"
52 /* For testing purposes */
53 /*#define MAIN_MENU_UI "ui/bluefish_menu_ui.xml"*/
54 /*#define MAIN_TOOLBAR_UI "ui/bluefish_toolbar_ui.xml"*/
55 
56 
57 /* document action callbacks */
58 
59 static void
ui_autocompletion_popup_show(GtkAction * action,gpointer user_data)60 ui_autocompletion_popup_show(GtkAction * action, gpointer user_data)
61 {
62 	Tbfwin *bfwin = BFWIN(user_data);
63 
64 	if (bfwin->current_document)
65 		bluefish_text_view_set_auto_complete(BLUEFISH_TEXT_VIEW(bfwin->current_document->view),
66 											 gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)));
67 }
68 
69 static void
ui_bookmark_toggle(GtkAction * action,gpointer user_data)70 ui_bookmark_toggle(GtkAction * action, gpointer user_data)
71 {
72 	bmark_toggle_at_cursor(BFWIN(user_data));
73 }
74 
75 static void
ui_encoding_add_remove(GtkAction * action,gpointer user_data)76 ui_encoding_add_remove(GtkAction * action, gpointer user_data)
77 {
78 	bluefish_encodings_dialog_new(BFWIN(user_data));
79 }
80 
81 static void
ui_floating_window(GtkAction * action,gpointer user_data)82 ui_floating_window(GtkAction * action, gpointer user_data)
83 {
84 	doc_floating_view_new(BFWIN(user_data));
85 }
86 
87 static void
ui_font_size_decrease(GtkAction * action,gpointer user_data)88 ui_font_size_decrease(GtkAction * action, gpointer user_data)
89 {
90 	Tbfwin *bfwin = BFWIN(user_data);
91 
92 	if (bfwin->current_document)
93 		doc_font_size(bfwin->current_document, -1);
94 }
95 
96 static void
ui_font_size_increase(GtkAction * action,gpointer user_data)97 ui_font_size_increase(GtkAction * action, gpointer user_data)
98 {
99 	Tbfwin *bfwin = BFWIN(user_data);
100 
101 	if (bfwin->current_document)
102 		doc_font_size(bfwin->current_document, 1);
103 }
104 
105 static void
ui_font_size_reset(GtkAction * action,gpointer user_data)106 ui_font_size_reset(GtkAction * action, gpointer user_data)
107 {
108 	Tbfwin *bfwin = BFWIN(user_data);
109 
110 	if (bfwin->current_document)
111 		doc_font_size(bfwin->current_document, 0);
112 }
113 
114 static void
ui_highlighting_toggle(GtkAction * action,gpointer user_data)115 ui_highlighting_toggle(GtkAction * action, gpointer user_data)
116 {
117 	Tbfwin *bfwin = BFWIN(user_data);
118 
119 	if (bfwin->current_document)
120 		doc_toggle_highlighting(bfwin, gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)));
121 }
122 
123 static void
ui_highlighting_update(GtkAction * action,gpointer user_data)124 ui_highlighting_update(GtkAction * action, gpointer user_data)
125 {
126 	Tbfwin *bfwin = BFWIN(user_data);
127 
128 	if (bfwin->current_document)
129 		doc_update_highlighting(bfwin, 0, NULL);
130 }
131 
132 static void
ui_move_tab_left(GtkAction * action,gpointer user_data)133 ui_move_tab_left(GtkAction * action, gpointer user_data)
134 {
135 	bfwin_notebook_switch(BFWIN(user_data), 5);
136 }
137 
138 static void
ui_move_tab_right(GtkAction * action,gpointer user_data)139 ui_move_tab_right(GtkAction * action, gpointer user_data)
140 {
141 	bfwin_notebook_switch(BFWIN(user_data), 6);
142 }
143 
144 static void
ui_reorder_tab_byfilename(GtkAction * action,gpointer user_data)145 ui_reorder_tab_byfilename(GtkAction * action, gpointer user_data)
146 {
147 	bfwin_notebook_switch(BFWIN(user_data), 8);
148 }
149 static void
ui_reorder_tab_byfullpath(GtkAction * action,gpointer user_data)150 ui_reorder_tab_byfullpath(GtkAction * action, gpointer user_data)
151 {
152 	bfwin_notebook_switch(BFWIN(user_data), 9);
153 }
154 
155 static void
ui_set_autoindent(GtkAction * action,gpointer user_data)156 ui_set_autoindent(GtkAction * action, gpointer user_data)
157 {
158 	Tbfwin *bfwin = BFWIN(user_data);
159 
160 	if (bfwin->current_document)
161 		bluefish_text_view_set_auto_indent(BLUEFISH_TEXT_VIEW(bfwin->current_document->view),
162 										   gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)));
163 }
164 
165 static void
ui_set_highlight_block_delimiters(GtkAction * action,gpointer user_data)166 ui_set_highlight_block_delimiters(GtkAction * action, gpointer user_data)
167 {
168 	Tbfwin *bfwin = BFWIN(user_data);
169 
170 	if (bfwin->current_document)
171 		bluefish_text_view_set_show_mbhl(BLUEFISH_TEXT_VIEW(bfwin->current_document->view),
172 										 gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)));
173 }
174 
175 #ifdef HAVE_LIBENCHANT
176 static void
ui_set_spell_check(GtkAction * action,gpointer user_data)177 ui_set_spell_check(GtkAction * action, gpointer user_data)
178 {
179 	Tbfwin *bfwin = BFWIN(user_data);
180 
181 	if (bfwin->current_document)
182 		bluefish_text_view_set_spell_check(BLUEFISH_TEXT_VIEW(bfwin->current_document->view),
183 										   gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)));
184 }
185 #endif
186 
187 static void
ui_set_wrap_text(GtkAction * action,gpointer user_data)188 ui_set_wrap_text(GtkAction * action, gpointer user_data)
189 {
190 	Tbfwin *bfwin = BFWIN(user_data);
191 
192 	if (bfwin->current_document) {
193 		doc_set_wrap(bfwin->current_document, gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)));
194 	}
195 }
196 
197 static void
ui_show_blocks(GtkAction * action,gpointer user_data)198 ui_show_blocks(GtkAction * action, gpointer user_data)
199 {
200 	Tbfwin *bfwin = BFWIN(user_data);
201 
202 	if (bfwin->current_document)
203 		bluefish_text_view_set_show_blocks(BLUEFISH_TEXT_VIEW(bfwin->current_document->view),
204 										   gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)));
205 }
206 
207 static void
ui_show_line_numbers(GtkAction * action,gpointer user_data)208 ui_show_line_numbers(GtkAction * action, gpointer user_data)
209 {
210 	Tbfwin *bfwin = BFWIN(user_data);
211 
212 	if (bfwin->current_document)
213 		bluefish_text_view_set_show_line_numbers(BLUEFISH_TEXT_VIEW(bfwin->current_document->view),
214 												 gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)));
215 }
216 
217 static void
ui_show_right_margin(GtkAction * action,gpointer user_data)218 ui_show_right_margin(GtkAction * action, gpointer user_data)
219 {
220 	Tbfwin *bfwin = BFWIN(user_data);
221 
222 	if (bfwin->current_document)
223 		bluefish_text_view_set_show_right_margin(BLUEFISH_TEXT_VIEW(bfwin->current_document->view),
224 												 gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)));
225 }
226 
227 static void
ui_show_split_view(GtkAction * action,gpointer user_data)228 ui_show_split_view(GtkAction * action, gpointer user_data)
229 {
230 	Tbfwin *bfwin = BFWIN(user_data);
231 
232 	if (bfwin->current_document)
233 		doc_split_view(CURDOC(bfwin), gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)));
234 }
235 
236 static void
ui_show_visible_spacing(GtkAction * action,gpointer user_data)237 ui_show_visible_spacing(GtkAction * action, gpointer user_data)
238 {
239 	Tbfwin *bfwin = BFWIN(user_data);
240 
241 	if (bfwin->current_document)
242 		bluefish_text_view_set_show_visible_spacing(BLUEFISH_TEXT_VIEW(bfwin->current_document->view),
243 													gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)));
244 }
245 
246 static void
ui_tab_size_decrease(GtkAction * action,gpointer user_data)247 ui_tab_size_decrease(GtkAction * action, gpointer user_data)
248 {
249 	Tbfwin *bfwin = BFWIN(user_data);
250 
251 	if (bfwin->current_document)
252 		doc_change_tabsize(bfwin->current_document, -1);
253 }
254 
255 static void
ui_tab_size_increase(GtkAction * action,gpointer user_data)256 ui_tab_size_increase(GtkAction * action, gpointer user_data)
257 {
258 	Tbfwin *bfwin = BFWIN(user_data);
259 
260 	if (bfwin->current_document)
261 		doc_change_tabsize(bfwin->current_document, 1);
262 }
263 
264 static void
ui_tab_size_reset(GtkAction * action,gpointer user_data)265 ui_tab_size_reset(GtkAction * action, gpointer user_data)
266 {
267 	Tbfwin *bfwin = BFWIN(user_data);
268 
269 	if (bfwin->current_document)
270 		doc_change_tabsize(bfwin->current_document, 0);
271 }
272 
273 /* edit action callbacks */
274 
275 static void
ui_redo(GtkAction * action,gpointer user_data)276 ui_redo(GtkAction * action, gpointer user_data)
277 {
278 	redo(BFWIN(user_data));
279 }
280 
281 static void
ui_redo_all(GtkAction * action,gpointer user_data)282 ui_redo_all(GtkAction * action, gpointer user_data)
283 {
284 	redo_all(BFWIN(user_data));
285 }
286 
287 static void
ui_undo(GtkAction * action,gpointer user_data)288 ui_undo(GtkAction * action, gpointer user_data)
289 {
290 	undo(BFWIN(user_data));
291 }
292 
293 static void
ui_undo_all(GtkAction * action,gpointer user_data)294 ui_undo_all(GtkAction * action, gpointer user_data)
295 {
296 	undo_all(BFWIN(user_data));
297 }
298 
299 static void
ui_copy(GtkAction * action,gpointer user_data)300 ui_copy(GtkAction * action, gpointer user_data)
301 {
302 	Tbfwin *bfwin = BFWIN(user_data);
303 
304 	if (bfwin->current_document)
305 		doc_copy(bfwin);
306 }
307 
308 static void
ui_cut(GtkAction * action,gpointer user_data)309 ui_cut(GtkAction * action, gpointer user_data)
310 {
311 	Tbfwin *bfwin = BFWIN(user_data);
312 
313 	if (bfwin->current_document)
314 		doc_cut(bfwin);
315 }
316 
317 static void
ui_paste(GtkAction * action,gpointer user_data)318 ui_paste(GtkAction * action, gpointer user_data)
319 {
320 	Tbfwin *bfwin = BFWIN(user_data);
321 	if (bfwin->current_document)
322 		doc_paste(bfwin);
323 }
324 
325 static void
ui_paste_special(GtkAction * action,gpointer user_data)326 ui_paste_special(GtkAction * action, gpointer user_data)
327 {
328 	Tbfwin *bfwin = BFWIN(user_data);
329 	if (bfwin->current_document)
330 		doc_paste_special(bfwin);
331 }
332 
333 static void
ui_find(GtkAction * action,gpointer user_data)334 ui_find(GtkAction * action, gpointer user_data)
335 {
336 	bfwin_simplesearch_show(BFWIN(user_data));
337 	/*snr_dialog_new(BFWIN(user_data), BF_FIND_DIALOG); */
338 }
339 
340 static void
ui_find_again(GtkAction * action,gpointer user_data)341 ui_find_again(GtkAction * action, gpointer user_data)
342 {
343 	simple_search_next(BFWIN(user_data));
344 }
345 
346 static void
ui_find_from_clipboard(GtkAction * action,gpointer user_data)347 ui_find_from_clipboard(GtkAction * action, gpointer user_data)
348 {
349 	bfwin_simplesearch_from_clipboard(BFWIN(user_data));
350 	/*search_from_selection(BFWIN(user_data)); */
351 }
352 
353 static void
ui_replace(GtkAction * action,gpointer user_data)354 ui_replace(GtkAction * action, gpointer user_data)
355 {
356 
357 	snr3_advanced_dialog(BFWIN(user_data), NULL);
358 	/*snr_dialog_new(BFWIN(user_data), BF_REPLACE_DIALOG); */
359 }
360 
361 /*static void
362 ui_replace_again(GtkAction * action, gpointer user_data)
363 {
364 	replace_again(BFWIN(user_data));
365 }
366 */
367 static void
ui_indent(GtkAction * action,gpointer user_data)368 ui_indent(GtkAction * action, gpointer user_data)
369 {
370 	Tbfwin *bfwin = BFWIN(user_data);
371 
372 	if (bfwin->current_document)
373 		doc_indent_selection(bfwin->current_document, FALSE);
374 }
375 
376 static void
ui_unindent(GtkAction * action,gpointer user_data)377 ui_unindent(GtkAction * action, gpointer user_data)
378 {
379 	Tbfwin *bfwin = BFWIN(user_data);
380 
381 	if (bfwin->current_document)
382 		doc_indent_selection(bfwin->current_document, TRUE);
383 }
384 
385 static void
ui_preferences(GtkAction * action,gpointer user_data)386 ui_preferences(GtkAction * action, gpointer user_data)
387 {
388 	Tbfwin *bfwin = BFWIN(user_data);
389 	preferences_dialog_new(bfwin);
390 }
391 
392 static void
ui_select_all(GtkAction * action,gpointer user_data)393 ui_select_all(GtkAction * action, gpointer user_data)
394 {
395 	Tbfwin *bfwin = BFWIN(user_data);
396 
397 	if (bfwin->current_document)
398 		doc_select_all(bfwin);
399 }
400 
401 /* file action callbacks */
402 
403 static void
ui_file_close(GtkAction * action,gpointer user_data)404 ui_file_close(GtkAction * action, gpointer user_data)
405 {
406 	Tbfwin *bfwin = BFWIN(user_data);
407 
408 	if (bfwin->current_document)
409 		doc_close_single_backend(bfwin->current_document, FALSE, FALSE);
410 }
411 
412 static void
ui_file_close_all(GtkAction * action,gpointer user_data)413 ui_file_close_all(GtkAction * action, gpointer user_data)
414 {
415 	file_close_all(BFWIN(user_data));
416 }
417 
418 static void
ui_file_reload(GtkAction * action,gpointer user_data)419 ui_file_reload(GtkAction * action, gpointer user_data)
420 {
421 	Tbfwin *bfwin = BFWIN(user_data);
422 
423 	if (bfwin->current_document)
424 		doc_reload(bfwin->current_document, NULL, TRUE);
425 }
426 
427 static void
ui_file_rename(GtkAction * action,gpointer user_data)428 ui_file_rename(GtkAction * action, gpointer user_data)
429 {
430 	Tbfwin *bfwin = BFWIN(user_data);
431 
432 	if (bfwin->current_document)
433 		doc_save_backend(bfwin->current_document, docsave_move, FALSE, FALSE);
434 }
435 
436 static void
ui_file_save_copy(GtkAction * action,gpointer user_data)437 ui_file_save_copy(GtkAction * action, gpointer user_data)
438 {
439 	Tbfwin *bfwin = BFWIN(user_data);
440 
441 	if (bfwin->current_document)
442 		doc_save_backend(bfwin->current_document, docsave_copy, FALSE, FALSE);
443 }
444 
445 static void
ui_file_save(GtkAction * action,gpointer user_data)446 ui_file_save(GtkAction * action, gpointer user_data)
447 {
448 	Tbfwin *bfwin = BFWIN(user_data);
449 
450 	if (bfwin->current_document)
451 		doc_save_backend(bfwin->current_document, docsave_normal, FALSE, FALSE);
452 }
453 
454 static void
ui_file_save_all(GtkAction * action,gpointer user_data)455 ui_file_save_all(GtkAction * action, gpointer user_data)
456 {
457 	file_save_all(BFWIN(user_data));
458 }
459 
460 static void
ui_file_save_as(GtkAction * action,gpointer user_data)461 ui_file_save_as(GtkAction * action, gpointer user_data)
462 {
463 	Tbfwin *bfwin = BFWIN(user_data);
464 
465 	if (bfwin->current_document)
466 		doc_save_backend(bfwin->current_document, docsave_saveas, FALSE, FALSE);
467 }
468 
469 static void
ui_insert_doc(GtkAction * action,gpointer user_data)470 ui_insert_doc(GtkAction * action, gpointer user_data)
471 {
472 	Tbfwin *bfwin = BFWIN(user_data);
473 
474 	if (bfwin->current_document)
475 		file_insert_doc(bfwin);
476 }
477 
478 static void
ui_print_doc(GtkAction * action,gpointer user_data)479 ui_print_doc(GtkAction * action, gpointer user_data)
480 {
481 	Tbfwin *bfwin = BFWIN(user_data);
482 	doc_print(bfwin->current_document);
483 }
484 
485 static void
ui_new_doc(GtkAction * action,gpointer user_data)486 ui_new_doc(GtkAction * action, gpointer user_data)
487 {
488 	file_new_doc(BFWIN(user_data));
489 }
490 
491 static void
ui_new_window(GtkAction * action,gpointer user_data)492 ui_new_window(GtkAction * action, gpointer user_data)
493 {
494 	bfwin_window_new();
495 }
496 
497 static void
ui_window_close(GtkAction * action,gpointer user_data)498 ui_window_close(GtkAction * action, gpointer user_data)
499 {
500 	bfwin_window_close(BFWIN(user_data));
501 }
502 
503 static void
ui_open_advanced(GtkAction * action,gpointer user_data)504 ui_open_advanced(GtkAction * action, gpointer user_data)
505 {
506 	files_advanced_win(BFWIN(user_data), NULL);
507 }
508 
509 static void
ui_open_doc(GtkAction * action,gpointer user_data)510 ui_open_doc(GtkAction * action, gpointer user_data)
511 {
512 	file_open_doc(BFWIN(user_data));
513 }
514 
515 static void
ui_open_from_selection(GtkAction * action,gpointer user_data)516 ui_open_from_selection(GtkAction * action, gpointer user_data)
517 {
518 	file_open_from_selection(BFWIN(user_data));
519 }
520 
521 static void
ui_upload_download_dialog(GtkAction * action,gpointer user_data)522 ui_upload_download_dialog(GtkAction * action, gpointer user_data)
523 {
524 	sync_dialog(BFWIN(user_data));
525 }
526 
527 static void
ui_quit(GtkAction * action,gpointer user_data)528 ui_quit(GtkAction * action, gpointer user_data)
529 {
530 	bluefish_exit_request();
531 }
532 
533 /* Go action callbacks */
534 static void
ui_bookmark_first(GtkAction * action,gpointer user_data)535 ui_bookmark_first(GtkAction * action, gpointer user_data)
536 {
537 	bookmark_navigate(BFWIN(user_data), 1);
538 }
539 
540 static void
ui_bookmark_last(GtkAction * action,gpointer user_data)541 ui_bookmark_last(GtkAction * action, gpointer user_data)
542 {
543 	bookmark_navigate(BFWIN(user_data), 4);
544 }
545 
546 static void
ui_bookmark_next(GtkAction * action,gpointer user_data)547 ui_bookmark_next(GtkAction * action, gpointer user_data)
548 {
549 	bookmark_navigate(BFWIN(user_data), 3);
550 }
551 
552 static void
ui_bookmark_previous(GtkAction * action,gpointer user_data)553 ui_bookmark_previous(GtkAction * action, gpointer user_data)
554 {
555 	bookmark_navigate(BFWIN(user_data), 2);
556 }
557 
558 static void
ui_doc_recent(GtkAction * action,gpointer user_data)559 ui_doc_recent(GtkAction * action, gpointer user_data)
560 {
561 	bfwin_notebook_switch(BFWIN(user_data), 7);
562 }
563 
564 static void
ui_doc_first(GtkAction * action,gpointer user_data)565 ui_doc_first(GtkAction * action, gpointer user_data)
566 {
567 	bfwin_notebook_switch(BFWIN(user_data), 3);
568 }
569 
570 static void
ui_doc_last(GtkAction * action,gpointer user_data)571 ui_doc_last(GtkAction * action, gpointer user_data)
572 {
573 	bfwin_notebook_switch(BFWIN(user_data), 4);
574 }
575 
576 static void
ui_doc_next(GtkAction * action,gpointer user_data)577 ui_doc_next(GtkAction * action, gpointer user_data)
578 {
579 	bfwin_notebook_switch(BFWIN(user_data), 2);
580 }
581 
582 static void
ui_doc_previous(GtkAction * action,gpointer user_data)583 ui_doc_previous(GtkAction * action, gpointer user_data)
584 {
585 	bfwin_notebook_switch(BFWIN(user_data), 1);
586 }
587 
588 static void
ui_goto_line(GtkAction * action,gpointer user_data)589 ui_goto_line(GtkAction * action, gpointer user_data)
590 {
591 	bfwin_gotoline_frame_show(BFWIN(user_data));
592 }
593 
594 static void
ui_goto_line_selection(GtkAction * action,gpointer user_data)595 ui_goto_line_selection(GtkAction * action, gpointer user_data)
596 {
597 	bfwin_gotoline_from_clipboard(BFWIN(user_data));
598 }
599 
600 static void
ui_jump_to_reference(GtkAction * action,gpointer user_data)601 ui_jump_to_reference(GtkAction * action, gpointer user_data)
602 {
603 	Tbfwin *bfwin = BFWIN(user_data);
604 
605 	if (bfwin->current_document)
606 		doc_jump(bfwin->current_document);
607 }
608 
609 static void
ui_jump_to_matching_block_boundary(GtkAction * action,gpointer user_data)610 ui_jump_to_matching_block_boundary(GtkAction * action, gpointer user_data)
611 {
612 	Tbfwin *bfwin = BFWIN(user_data);
613 
614 	if (bfwin->current_document)
615 		doc_jump_matching_block_boundary(bfwin->current_document);
616 }
617 
618 /* project action callbacks */
619 
620 static void
ui_project_close(GtkAction * action,gpointer user_data)621 ui_project_close(GtkAction * action, gpointer user_data)
622 {
623 	project_save_and_close(BFWIN(user_data));
624 }
625 
626 static void
ui_project_edit_options(GtkAction * action,gpointer user_data)627 ui_project_edit_options(GtkAction * action, gpointer user_data)
628 {
629 	project_edit(BFWIN(user_data));
630 }
631 
632 static void
ui_project_new(GtkAction * action,gpointer user_data)633 ui_project_new(GtkAction * action, gpointer user_data)
634 {
635 	project_new(BFWIN(user_data));
636 }
637 
638 static void
ui_project_open(GtkAction * action,gpointer user_data)639 ui_project_open(GtkAction * action, gpointer user_data)
640 {
641 	project_open(BFWIN(user_data));
642 }
643 
644 static void
ui_project_save(GtkAction * action,gpointer user_data)645 ui_project_save(GtkAction * action, gpointer user_data)
646 {
647 	project_save(BFWIN(user_data), FALSE);
648 }
649 
650 static void
ui_project_save_as(GtkAction * action,gpointer user_data)651 ui_project_save_as(GtkAction * action, gpointer user_data)
652 {
653 	project_save(BFWIN(user_data), TRUE);
654 }
655 
656 /* tools action callbacks */
657 
658 static void
ui_indenting_to_spaces(GtkAction * action,gpointer user_data)659 ui_indenting_to_spaces(GtkAction * action, gpointer user_data)
660 {
661 	convert_identing(BFWIN(user_data)->current_document, FALSE);
662 }
663 
664 static void
ui_indenting_to_tabs(GtkAction * action,gpointer user_data)665 ui_indenting_to_tabs(GtkAction * action, gpointer user_data)
666 {
667 	convert_identing(BFWIN(user_data)->current_document, TRUE);
668 }
669 
670 static void
ui_join_lines(GtkAction * action,gpointer user_data)671 ui_join_lines(GtkAction * action, gpointer user_data)
672 {
673 	join_lines(BFWIN(user_data)->current_document);
674 }
675 
676 static void
ui_merge_lines(GtkAction * action,gpointer user_data)677 ui_merge_lines(GtkAction * action, gpointer user_data)
678 {
679 	convert_to_columns(BFWIN(user_data)->current_document);
680 }
681 
682 static void
ui_select_block(GtkAction * action,gpointer user_data)683 ui_select_block(GtkAction * action, gpointer user_data)
684 {
685 	select_between_matching_block_boundaries(BFWIN(user_data)->current_document);
686 }
687 
688 static void
ui_select_identifier(GtkAction * action,gpointer user_data)689 ui_select_identifier(GtkAction * action, gpointer user_data)
690 {
691 	select_current_identifier(BFWIN(user_data)->current_document);
692 }
693 
694 static void
ui_duplicate_line(GtkAction * action,gpointer user_data)695 ui_duplicate_line(GtkAction * action, gpointer user_data)
696 {
697 	duplicate_line(BFWIN(user_data)->current_document);
698 }
699 
700 static void
ui_delete_line(GtkAction * action,gpointer user_data)701 ui_delete_line(GtkAction * action, gpointer user_data)
702 {
703 	delete_line(BFWIN(user_data)->current_document);
704 }
705 
706 static void
ui_rewrap_lines(GtkAction * action,gpointer user_data)707 ui_rewrap_lines(GtkAction * action, gpointer user_data)
708 {
709 	rewrap_lines(BFWIN(user_data)->current_document);
710 }
711 
712 static void
ui_split_lines(GtkAction * action,gpointer user_data)713 ui_split_lines(GtkAction * action, gpointer user_data)
714 {
715 	split_lines(BFWIN(user_data)->current_document);
716 }
717 
718 static void
ui_strip_trailing_whitespace(GtkAction * action,gpointer user_data)719 ui_strip_trailing_whitespace(GtkAction * action, gpointer user_data)
720 {
721 	strip_trailing_spaces(BFWIN(user_data)->current_document);
722 }
723 
724 static void
ui_synch_text_block(GtkAction * action,gpointer user_data)725 ui_synch_text_block(GtkAction * action, gpointer user_data)
726 {
727 	blocksync_dialog(BFWIN(user_data));
728 }
729 
730 static void
ui_toggle_comment(GtkAction * action,gpointer user_data)731 ui_toggle_comment(GtkAction * action, gpointer user_data)
732 {
733 	toggle_comment(BFWIN(user_data)->current_document);
734 }
735 
736 static void
ui_word_count(GtkAction * action,gpointer user_data)737 ui_word_count(GtkAction * action, gpointer user_data)
738 {
739 	Tbfwin *bfwin = BFWIN(user_data);
740 
741 	if (bfwin->current_document)
742 		doc_word_count(bfwin);
743 }
744 
745 static void
ui_lorem_ipsum(GtkAction * action,gpointer user_data)746 ui_lorem_ipsum(GtkAction * action, gpointer user_data)
747 {
748 	lorem_ipsum_dialog(BFWIN(user_data));
749 }
750 
751 static void
ui_jsbeautify(GtkAction * action,gpointer user_data)752 ui_jsbeautify(GtkAction * action, gpointer user_data)
753 {
754 	jsbeautify_dialog(BFWIN(user_data));
755 }
756 
757 
758 static void
ui_insert_relative_filename(GtkAction * action,gpointer user_data)759 ui_insert_relative_filename(GtkAction * action, gpointer user_data)
760 {
761 	doc_insert_filename(BFWIN(user_data)->current_document, TRUE);
762 }
763 
764 static void
ui_insert_absolute_filename(GtkAction * action,gpointer user_data)765 ui_insert_absolute_filename(GtkAction * action, gpointer user_data)
766 {
767 	doc_insert_filename(BFWIN(user_data)->current_document, FALSE);
768 }
769 
770 /* view action callbacks */
771 
772 void
sync_fullscreen_toggle(Tbfwin * bfwin,gboolean is_fullscreen)773 sync_fullscreen_toggle(Tbfwin * bfwin, gboolean is_fullscreen)
774 {
775 	GtkAction *action = gtk_ui_manager_get_action(bfwin->uimanager, "/MainToolbar/ViewFullScreen");
776 	/* TODO: This only works when "use-action-appearance" is TRUE. TRUE is default */
777 	gtk_action_set_stock_id(action, (is_fullscreen ? GTK_STOCK_LEAVE_FULLSCREEN : GTK_STOCK_FULLSCREEN));
778 	gtk_action_set_tooltip(action, (is_fullscreen ? _("Leave Fullscreen") : _("Fullscreen")));
779 	if (gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)) != is_fullscreen) {
780 		gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), is_fullscreen);
781 	}
782 }
783 
784 static void
ui_fullscreen_toggle(GtkAction * action,gpointer user_data)785 ui_fullscreen_toggle(GtkAction * action, gpointer user_data)
786 {
787 	bfwin_fullscreen_toggle(BFWIN(user_data), gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)));
788 }
789 
790 static void
ui_main_toolbar_show(GtkAction * action,gpointer user_data)791 ui_main_toolbar_show(GtkAction * action, gpointer user_data)
792 {
793 	bfwin_main_toolbar_show(BFWIN(user_data), gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)));
794 }
795 
796 static void
ui_output_pane_show(GtkAction * action,gpointer user_data)797 ui_output_pane_show(GtkAction * action, gpointer user_data)
798 {
799 	bfwin_output_pane_show(BFWIN(user_data), gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)));
800 }
801 
802 static void
ui_side_pane_show(GtkAction * action,gpointer user_data)803 ui_side_pane_show(GtkAction * action, gpointer user_data)
804 {
805 	bfwin_side_panel_show(BFWIN(user_data), gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)));
806 }
807 
808 static void
ui_statusbar_show(GtkAction * action,gpointer user_data)809 ui_statusbar_show(GtkAction * action, gpointer user_data)
810 {
811 	bfwin_statusbar_show(BFWIN(user_data), gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)));
812 }
813 
814 static void
ui_browser_preview(GtkAction * action,gpointer user_data)815 ui_browser_preview(GtkAction * action, gpointer user_data)
816 {
817 	GList *list;
818 	DEBUG_MSG("ui_browser_preview\n");
819 	/* TODO find the default browser and start it */
820 	for (list = g_list_first(main_v->props.external_command); list; list = list->next) {
821 		gchar **arr = list->data;
822 		/* arr[0] = enabled
823 		 * arr[1] = name
824 		 * arr[2] = command
825 		 * arr[3] = is_default_browser
826 		 */
827 		if (g_strv_length(arr) == 4 && arr[3][0] == '1') {
828 			DEBUG_MSG("ui_browser_preview, start %s\n", arr[2]);
829 			external_command(BFWIN(user_data), arr[2]);
830 		}
831 	}
832 }
833 
834 
835 static const GtkActionEntry top_level_menus[] = {
836 	{"FileMenu", NULL, N_("_File")},
837 	{"NewFromTemplate", NULL, N_("New From Template")},
838 	{"FileOpenRecent", NULL, N_("Open _Recent")},
839 	{"EditMenu", NULL, N_("_Edit")},
840 	{"ViewMenu", NULL, N_("_View")},
841 	{"DocumentMenu", NULL, N_("_Document")},
842 	{"DocumentTabSize", NULL, N_("_Tab Size")},
843 	{"DocumentFontSize", NULL, N_("_Font Size")},
844 	{"DocumentLangMode", NULL, N_("Language M_ode")},
845 	{"DocumentEncoding", NULL, N_("Character _Encoding")},
846 	{"DocReorder", NULL, N_("Reorder documents")},
847 	{"GoMenu", NULL, N_("_Go")},
848 	{"ProjectMenu", NULL, N_("_Project")},
849 	{"ProjectOpenRecent", NULL, N_("Open _Recent")},
850 	{"ToolsMenu", NULL, N_("_Tools")},
851 	{"ToolsCommands", NULL, N_("_Commands")},
852 	{"ToolsFilters", NULL, N_("_Filters")},
853 	{"ToolsOutputBox", NULL, N_("_Output parsers")},
854 	{"ToolsFormat", NULL, N_("For_mat")},
855 	{"ToolsInsert", NULL, N_("_Insert")},
856 	{"ToolsConvert", NULL, N_("Con_vert")}
857 };
858 
859 static const GtkActionEntry global_actions[] = {
860 	{"FileNew", GTK_STOCK_NEW, N_("_New"), "<control>N", N_("New file"), G_CALLBACK(ui_new_doc)},
861 	{"FileNewWindow", NULL, N_("New _Window"), "<shift><control>N", N_("New window"),
862 	 G_CALLBACK(ui_new_window)},
863 	{"FileCloseWindow", NULL, N_("Close Win_dow"), NULL, N_("Close window"), G_CALLBACK(ui_window_close)},
864 	{"FileOpen", GTK_STOCK_OPEN, N_("_Open..."), "<control>O", N_("Open file"), G_CALLBACK(ui_open_doc)},
865 	{"FileOpenAdvanced", NULL, N_("Open Ad_vanced..."), "<shift><control>O", N_("Open advanced"),
866 	 G_CALLBACK(ui_open_advanced)},
867 	{"FileOpenSelection", NULL, N_("Open _from Selection"), NULL, N_("Open from Selection"),
868 	 G_CALLBACK(ui_open_from_selection)},
869 	{"FilePrint", NULL, N_("_Print..."), NULL, N_("Print"), G_CALLBACK(ui_print_doc)},
870 	{"FileQuit", GTK_STOCK_QUIT, N_("_Quit"), "<control>Q", N_("Quit Bluefish"), G_CALLBACK(ui_quit)},
871 #ifdef MAC_INTEGRATION
872 	{"EditPreferences", GTK_STOCK_PREFERENCES, N_("Preference_s..."), "<control>comma", N_("Edit Preferences"),
873 	 G_CALLBACK(ui_preferences)},
874 #else
875 	{"EditPreferences", GTK_STOCK_PREFERENCES, N_("Preference_s..."), NULL, N_("Edit Preferences"),
876 	 G_CALLBACK(ui_preferences)},
877 #endif
878 	{"EditSelectAll", NULL, N_("Select _All"), "<control>A", N_("Select all"), G_CALLBACK(ui_select_all)},
879 	{"DocAddBookmark", NULL, N_("Toggle Boo_kmark"), "<control>k", N_("Toggle bookmark"),
880 	 G_CALLBACK(ui_bookmark_toggle)},
881 	{"DocEncodingAddRemove", NULL, N_("_Add or Remove..."), NULL, N_("Add or remove character encoding"),
882 	 G_CALLBACK(ui_encoding_add_remove)},
883 	{"DocFloatingWindow", NULL, N_("Floati_ng Window"), NULL, N_("Open current document in floating window"),
884 	 G_CALLBACK(ui_floating_window)},
885 	{"DocFontSizeIncrease", NULL, N_("_Increase"), "<control>equal", N_("Increase document font size"),
886 	 G_CALLBACK(ui_font_size_increase)},
887 	{"DocFontSizeDecrease", NULL, N_("_Decrease"), "<control>minus", N_("Decrease document font size"),
888 	 G_CALLBACK(ui_font_size_decrease)},
889 	{"DocFontSizeReset", NULL, N_("_Reset"), "<Control>KP_0", N_("Reset document font size"),
890 	 G_CALLBACK(ui_font_size_reset)},
891 	{"DocTabSizeIncrease", NULL, N_("_Increase"), NULL, N_("Increase document tab size"),
892 	 G_CALLBACK(ui_tab_size_increase)},
893 	{"DocTabSizeDecrease", NULL, N_("_Decrease"), NULL, N_("Decrease document tab size"),
894 	 G_CALLBACK(ui_tab_size_decrease)},
895 	{"DocTabSizeReset", NULL, N_("_Reset"), NULL, N_("Reset document tab size"),
896 	 G_CALLBACK(ui_tab_size_reset)},
897 #ifdef HAVE_LIBENCHANT
898 	{"DocumentRescan", NULL, N_("Rescan Synta_x & Spelling"), "F5", N_("Rescan document highlighting"),
899 	 G_CALLBACK(ui_highlighting_update)},
900 #else
901 	{"DocumentRescan", NULL, N_("Rescan Synta_x"), "F5", N_("Rescan document highlighting"),
902 	 G_CALLBACK(ui_highlighting_update)},
903 #endif
904 	{"ProjectNew", NULL, N_("_New Project..."), NULL, N_("New project"), G_CALLBACK(ui_project_new)},
905 	{"ProjectOpen", NULL, N_("_Open Project..."), NULL, N_("Open project"), G_CALLBACK(ui_project_open)},
906 	{"SynchTextBlock", NULL, N_("_Synchronize Text Block"), NULL, N_("Synchronize text block"),
907 	 G_CALLBACK(ui_synch_text_block)},
908 	{"ToggleComment", NULL, N_("_Toggle Comment"), "<shift><control>C", N_("Toggle comment"),
909 	 G_CALLBACK(ui_toggle_comment)},
910 	{"SelectBlock", NULL, N_("Select _Block"), "<shift><control>b",
911 	 N_("Select block, use multiple times to select parent blocks "),
912 	 G_CALLBACK(ui_select_block)},
913 	{"SelectIdentifier", NULL, N_("Select _Identifier"), "<shift><control>i",
914 	 N_("Select identifier"), G_CALLBACK(ui_select_identifier)},
915 	{"DuplicateLine", NULL, N_("D_uplicate Line"), "<control>d", N_("Duplicate the current line"),
916 	 G_CALLBACK(ui_duplicate_line)},
917 	{"DeleteLine", NULL, N_("_Delete Line"), "<control>y", N_("Delete the current line"),
918 	 G_CALLBACK(ui_delete_line)},
919 	{"WordCount", NULL, N_("_Word Count"), NULL, N_("Word count"), G_CALLBACK(ui_word_count)},
920 	{"LoremIpsum", NULL, N_("Lorem Ipsum generator"), NULL, N_("Lorem Ipsum generator"),
921 	 G_CALLBACK(ui_lorem_ipsum)},
922 	{"RelativeFilename", NULL, N_("Insert Relative Filename"), NULL, N_("Insert Relative Filename"),
923 	 G_CALLBACK(ui_insert_relative_filename)},
924 	{"AbsoluteFilename", NULL, N_("Insert Absolute Filename"), NULL, N_("Insert Absolute Filename"),
925 	 G_CALLBACK(ui_insert_absolute_filename)},
926 	{"IndentingToSpaces", NULL, N_("Indenting to S_paces"), NULL, N_("Indenting to spaces"),
927 	 G_CALLBACK(ui_indenting_to_spaces)},
928 	{"IndentingToTabs", NULL, N_("Indenting to T_abs"), NULL, N_("Indenting to tabs"),
929 	 G_CALLBACK(ui_indenting_to_tabs)},
930 	{"JoinLines", NULL, N_("_Join Lines Together"), NULL, N_("Join lines together"),
931 	 G_CALLBACK(ui_join_lines)},
932 	{"SplitLines", NULL, N_("Split Lines on Right _Margin"), NULL, N_("Split lines on right margin"),
933 	 G_CALLBACK(ui_split_lines)},
934 	{"MergeLinesIntoColumns", NULL, N_("Merge Lines Into Col_umns"), NULL, N_("Merge lines into columns"),
935 	 G_CALLBACK(ui_merge_lines)},
936 	{"RewrapLines", NULL, N_("Rewrap _Lines"), NULL, N_("Rewrap lines"), G_CALLBACK(ui_rewrap_lines)},
937 	{"StripTrailingWhitespace", NULL, N_("Strip T_railing Whitespace"), NULL, N_("Strip trailing whitespace"),
938 	 G_CALLBACK(ui_strip_trailing_whitespace)},
939 	{"JsBeautify", NULL, N_("Javascript beautifier"), NULL, N_("Javascript beautifier"),
940 	 G_CALLBACK(ui_jsbeautify)},
941 	{"BrowserPreview", BF_STOCK_BROWSER_PREVIEW, N_("Preview in browser"), NULL, N_("Preview in browser"),
942 	 G_CALLBACK(ui_browser_preview)}
943 };
944 
945 static const GtkToggleActionEntry global_toggle_actions[] = {
946 	{"ViewFullScreen", GTK_STOCK_FULLSCREEN, N_("_Full Screen"), "F11", N_("Full screen"),
947 	 G_CALLBACK(ui_fullscreen_toggle), FALSE},
948 	{"ViewMainToolbar", NULL, N_("_Main Toolbar"), NULL, N_("Show main toolbar"),
949 	 G_CALLBACK(ui_main_toolbar_show), TRUE},
950 	{"ViewSidePane", NULL, N_("_Side Pane"), "F9", N_("Show side pane"), G_CALLBACK(ui_side_pane_show), TRUE},
951 	{"ViewOutputPane", NULL, N_("_Output Pane"), "<control>F9", N_("Show output pane"),
952 	 G_CALLBACK(ui_output_pane_show), FALSE},
953 	{"ViewStatusbar", NULL, N_("Status_bar"), NULL, N_("Show statusbar"), G_CALLBACK(ui_statusbar_show),
954 	 TRUE},
955 	{"AutoCompletion", NULL, N_("Auto _Completion Popup"), NULL, N_("Show auto completion popup"),
956 	 G_CALLBACK(ui_autocompletion_popup_show), TRUE},
957 	{"AutoIndent", NULL, N_("_Auto Indent"), NULL, N_("Auto indent"), G_CALLBACK(ui_set_autoindent), TRUE},
958 	{"HighlightBlockDelimiters", NULL, N_("Highlight Block _Delimiters"), NULL,
959 	 N_("Highlight block delimiters"), G_CALLBACK(ui_set_highlight_block_delimiters), TRUE},
960 	{"HighlightSyntax", NULL, N_("_Highlight Syntax"), NULL, N_("Highlight syntax"),
961 	 G_CALLBACK(ui_highlighting_toggle), TRUE},
962 	{"ShowBlocks", NULL, N_("Show _Blocks"), NULL, N_("Show blocks"), G_CALLBACK(ui_show_blocks), TRUE},
963 	{"ShowLineNumbers", NULL, N_("Show Line N_umbers"), NULL, N_("Show line numbers"),
964 	 G_CALLBACK(ui_show_line_numbers), TRUE},
965 	{"ShowRightMargin", NULL, N_("Show Right _Margin"), NULL, N_("Show right margin"),
966 	 G_CALLBACK(ui_show_right_margin), FALSE},
967 	{"ShowSplitView", NULL, N_("Show Split _View"), NULL, N_("Show split view"),
968 	 G_CALLBACK(ui_show_split_view), FALSE},
969 	{"ShowVisibleSpacing", NULL, N_("Show V_isible Spacing"), NULL, N_("Show visible spacing"),
970 	 G_CALLBACK(ui_show_visible_spacing), FALSE},
971 	{"WrapText", NULL, N_("_Wrap Text"), NULL, N_("Wrap text"), G_CALLBACK(ui_set_wrap_text), FALSE}
972 };
973 
974 static const GtkActionEntry document_actions[] = {
975 	{"FileClose", GTK_STOCK_CLOSE, N_("_Close"), "<control>W", N_("Close current file"),
976 	 G_CALLBACK(ui_file_close)},
977 	{"FileCloseAll", NULL, N_("Close A_ll"), "<shift><control>W", N_("Close all files"),
978 	 G_CALLBACK(ui_file_close_all)},
979 	{"FileSave", GTK_STOCK_SAVE, N_("_Save"), "<control>S", N_("Save current file"),
980 	 G_CALLBACK(ui_file_save)},
981 	{"FileSaveAs", GTK_STOCK_SAVE_AS, N_("Save _as..."), "<shift><control>S", N_("Save file as"),
982 	 G_CALLBACK(ui_file_save_as)},
983 	{"FileSaveAll", NULL, N_("Sav_e All"), "<alt><shift>s", N_("Save all files"),
984 	 G_CALLBACK(ui_file_save_all)},
985 	{"FileRevert", GTK_STOCK_REVERT_TO_SAVED, N_("Rever_t to Saved"), NULL, N_("Reload current file"),
986 	 G_CALLBACK(ui_file_reload)},
987 	{"FileSaveCopy", NULL, N_("Save a cop_y..."), "<shift><control>y", N_("Save a copy"),
988 	 G_CALLBACK(ui_file_save_copy)},
989 	{"FileInsert", NULL, N_("_Insert..."), NULL, N_("Insert file"), G_CALLBACK(ui_insert_doc)},	/* Required to move here to disable sensitivity on OSX */
990 	{"FileRename", NULL, N_("Rena_me..."), "F2", N_("Rename file"), G_CALLBACK(ui_file_rename)},
991 #ifdef MAC_INTEGRATION			/* On Mac we configure this to alt and then moving them to control */
992 	{"EditIndent", GTK_STOCK_INDENT, N_("_Indent"), "<alt>period", N_("Indent"), G_CALLBACK(ui_indent)},
993 	{"EditUnindent", GTK_STOCK_UNINDENT, N_("Unin_dent"), "<alt>comma", N_("Unindent"),
994 #else
995 	{"EditIndent", GTK_STOCK_INDENT, N_("_Indent"), "<control>period", N_("Indent"), G_CALLBACK(ui_indent)},
996 	{"EditUnindent", GTK_STOCK_UNINDENT, N_("Unin_dent"), "<control>comma", N_("Unindent"),
997 #endif
998 	 G_CALLBACK(ui_unindent)},
999 	{"BookmarkFirst", GTK_STOCK_GOTO_TOP, N_("F_irst Bookmark"), NULL, N_("Goto first bookmark"),
1000 	 G_CALLBACK(ui_bookmark_first)},
1001 	{"BookmarkLast", GTK_STOCK_GOTO_BOTTOM, N_("L_ast Bookmark"), NULL, N_("Goto last bookmark"),
1002 	 G_CALLBACK(ui_bookmark_last)},
1003 	{"BookmarkNext", GTK_STOCK_GO_DOWN, N_("N_ext Bookmark"), "<shift><control>K", N_("Goto next bookmark"),
1004 	 G_CALLBACK(ui_bookmark_next)},
1005 	{"BookmarkPrevious", GTK_STOCK_GO_UP, N_("P_revious Bookmark"), "<shift><control>J",
1006 	 N_("Goto previous document"), G_CALLBACK(ui_bookmark_previous)},
1007 	{"DocMoveLeft", NULL, N_("Move Tab _Left"), NULL, N_("Move current tab left"),
1008 	 G_CALLBACK(ui_move_tab_left)},
1009 	{"DocMoveRight", NULL, N_("Move Tab _Right"), NULL, N_("Move current tab right"),
1010 	 G_CALLBACK(ui_move_tab_right)},
1011 	 {"DocReorderByfilename", NULL, N_("Sort by filename"), NULL, N_("Sort by filename"),
1012 	 G_CALLBACK(ui_reorder_tab_byfilename)},
1013 	 {"DocReorderByfullpath", NULL, N_("Sort by full path"), NULL, N_("Sort by full path"),
1014 	 G_CALLBACK(ui_reorder_tab_byfullpath)},
1015 	{"DocRecent", NULL, N_("_Recent Document"), "<control>Tab", N_("Goto most recent document"),
1016 	 G_CALLBACK(ui_doc_recent)},
1017 #ifdef MAC_INTEGRATION			/* On Mac keyboard we do not have Home, PageUp etc keys. We configure this to alt and then moving them to control */
1018 	{"DocFirst", GTK_STOCK_GOTO_FIRST, N_("_First Document"), "<shift><alt>Left",
1019 	 N_("Goto first document"),
1020 	 G_CALLBACK(ui_doc_first)},
1021 	{"DocLast", GTK_STOCK_GOTO_LAST, N_("_Last Document"), "<shift><alt>Right",
1022 	 N_("Goto last document"),
1023 	 G_CALLBACK(ui_doc_last)},
1024 	{"DocNext", GTK_STOCK_GO_FORWARD, N_("_Next Document"), "<alt>Right", N_("Goto next document"),
1025 	 G_CALLBACK(ui_doc_next)},
1026 	{"DocPrevious", GTK_STOCK_GO_BACK, N_("_Previous Document"), "<alt>Left",
1027 	 N_("Goto previous document"),
1028 	 G_CALLBACK(ui_doc_previous)},
1029 #else
1030 	{"DocFirst", GTK_STOCK_GOTO_FIRST, N_("_First Document"), "<shift><control>Page_Up",
1031 	 N_("Goto first document"),
1032 	 G_CALLBACK(ui_doc_first)},
1033 	{"DocLast", GTK_STOCK_GOTO_LAST, N_("_Last Document"), "<shift><control>Page_Down",
1034 	 N_("Goto last document"),
1035 	 G_CALLBACK(ui_doc_last)},
1036 	{"DocNext", GTK_STOCK_GO_FORWARD, N_("_Next Document"), "<control>Page_Down", N_("Goto next document"),
1037 	 G_CALLBACK(ui_doc_next)},
1038 	{"DocPrevious", GTK_STOCK_GO_BACK, N_("_Previous Document"), "<control>Page_Up",
1039 	 N_("Goto previous document"),
1040 	 G_CALLBACK(ui_doc_previous)},
1041 #endif
1042 	{"GotoLine", NULL, N_("_Goto Line"), "<control>L", N_("Goto line"), G_CALLBACK(ui_goto_line)},
1043 	{"GotoLineSelection", NULL, N_("Goto Line Number from _Clipboard"), "<shift><control>L",
1044 	 N_("Goto line number in clipboard or selection"), G_CALLBACK(ui_goto_line_selection)},
1045 	{"JumpToReference", NULL, N_("_Jump to Reference"), "<control>J", N_("Jump to reference"),
1046 	 G_CALLBACK(ui_jump_to_reference)},
1047 #ifdef MAC_INTEGRATION			/* On Mac Cmd+m is reserved for Minimise Window shortcut */
1048 	{"JumpToMatchingBlockBoundary", NULL, N_("Jump to Matching Block Boundary"), "<shift><control>M",
1049 	 N_("Jump to Matching Block Boundary"),
1050 	 G_CALLBACK(ui_jump_to_matching_block_boundary)}
1051 #else
1052 	{"JumpToMatchingBlockBoundary", NULL, N_("Jump to Matching Block Boundary"), "<control>m",
1053 	 N_("Jump to Matching Block Boundary"),
1054 	 G_CALLBACK(ui_jump_to_matching_block_boundary)}
1055 #endif
1056 };
1057 
1058 static const GtkActionEntry edit_actions[] = {
1059 	{"Cut", GTK_STOCK_CUT, N_("Cu_t"), "<control>X", N_("Cut"), G_CALLBACK(ui_cut)},
1060 	{"Copy", GTK_STOCK_COPY, N_("_Copy"), "<control>C", N_("Copy"), G_CALLBACK(ui_copy)},
1061 	{"Paste", GTK_STOCK_PASTE, N_("_Paste"), "<control>V", N_("Paste"), G_CALLBACK(ui_paste)},
1062 	{"PasteSpecial", GTK_STOCK_PASTE, N_("Paste Specia_l"), "<control><shift>v", N_("Paste Special"),
1063 	 G_CALLBACK(ui_paste_special)},
1064 };
1065 
1066 static const GtkActionEntry find_replace_actions[] = {
1067 	{"Find", GTK_STOCK_FIND, N_("_Find"), "<control>F", N_("Show find bar"), G_CALLBACK(ui_find)},
1068 	{"FindAgain", NULL, N_("Find A_gain"), "<control>G", N_("Find again"), G_CALLBACK(ui_find_again)},
1069 	{"FindSelection", NULL, N_("Find from Clip_board"), "<shift><control>F",
1070 	 N_("Find from clipboard or selection"),
1071 	 G_CALLBACK(ui_find_from_clipboard)},
1072 #ifdef MAC_INTEGRATION			/* On Mac Cmd+H is reserved for Hide Application shortcut */
1073 	{"Replace", GTK_STOCK_FIND_AND_REPLACE, N_("Ad_vanced Find & Replace..."), "<shift><control>H",
1074 	 N_("Advanced Find and Replace"),
1075 	 G_CALLBACK(ui_replace)}
1076 #else
1077 	{"Replace", GTK_STOCK_FIND_AND_REPLACE, N_("Ad_vanced Find & Replace..."), "<control>H",
1078 	 N_("Advanced Find and Replace"),
1079 	 G_CALLBACK(ui_replace)}
1080 #endif
1081 /*,
1082 	{"ReplaceAgain", NULL, N_("Replace Agai_n"), "<shift><control>H", N_("Replace again"),
1083 	 G_CALLBACK(ui_replace_again)}*/
1084 };
1085 
1086 static const GtkActionEntry project_actions[] = {
1087 	{"ProjectClose", NULL, N_("Save & _close"), NULL, N_("Save & close project"),
1088 	 G_CALLBACK(ui_project_close)},
1089 	{"ProjectSave", NULL, N_("_Save"), NULL, N_("Save project"), G_CALLBACK(ui_project_save)},
1090 	{"ProjectSaveAs", NULL, N_("Save _as..."), NULL, N_("Save project as"), G_CALLBACK(ui_project_save_as)},
1091 	{"ProjectEditOptions", NULL, N_("_Edit Project Options..."), NULL, N_("Edit project options"),
1092 	 G_CALLBACK(ui_project_edit_options)},
1093 };
1094 
1095 static const GtkActionEntry undo_redo_actions[] = {
1096 	{"Undo", GTK_STOCK_UNDO, N_("_Undo"), "<control>Z", N_("Undo"), G_CALLBACK(ui_undo)},
1097 	{"UndoAll", NULL, N_("U_ndo All"), NULL, N_("Undo All"), G_CALLBACK(ui_undo_all)},
1098 	{"Redo", GTK_STOCK_REDO, N_("_Redo"), "<shift><control>Z", N_("Redo"), G_CALLBACK(ui_redo)},
1099 	{"RedoAll", NULL, N_("R_edo All"), NULL, N_("Redo All"), G_CALLBACK(ui_redo_all)}
1100 };
1101 
1102 static void
dynamic_menu_empty(GtkUIManager * uimanager,guint merge_id,GtkActionGroup * action_group)1103 dynamic_menu_empty(GtkUIManager * uimanager, guint merge_id, GtkActionGroup * action_group)
1104 {
1105 	GList *actions, *list;
1106 
1107 	gtk_ui_manager_remove_ui(uimanager, merge_id);
1108 	actions = gtk_action_group_list_actions(action_group);
1109 	for (list = actions; list; list = list->next) {
1110 		DEBUG_MSG("dynamic_menu_empty, remove action %s\n", gtk_action_get_label(list->data));
1111 		/*g_signal_handlers_disconnect_by_func(GTK_ACTION(list->data),
1112 		   G_CALLBACK(commands_menu_activate), bfwin); */
1113 		gtk_action_group_remove_action(action_group, GTK_ACTION(list->data));
1114 	}
1115 	g_list_free(actions);
1116 }
1117 
1118 static void
ask_register_custom_mime_for_bflang(Tbfwin * bfwin,Tbflang * bflang,const gchar * mime)1119 ask_register_custom_mime_for_bflang(Tbfwin * bfwin, Tbflang * bflang, const gchar * mime)
1120 {
1121 	GtkWidget *dialog;
1122 	gint response;
1123 	dialog =
1124 		gtk_message_dialog_new(GTK_WINDOW(bfwin->main_window), GTK_DIALOG_DESTROY_WITH_PARENT,
1125 							   GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
1126 							   _("Always use this syntax for files of type %s ?"), mime);
1127 	response = gtk_dialog_run(GTK_DIALOG(dialog));
1128 	if (response == GTK_RESPONSE_YES) {
1129 		langmgr_add_custom_mime(bflang, mime);
1130 	}
1131 	gtk_widget_destroy(dialog);
1132 }
1133 
1134 static void
lang_mode_menu_activate(GtkAction * action,gpointer user_data)1135 lang_mode_menu_activate(GtkAction * action, gpointer user_data)
1136 {
1137 	Tbfwin *bfwin = BFWIN(user_data);
1138 	Tdocument *doc = bfwin->current_document;
1139 	Tbflang *bflang = g_object_get_data(G_OBJECT(action), "bflang");
1140 	DEBUG_MSG("lang_mode_menu_activate, bfwin=%p, action=%p, active=%d, bflang=%p (%s)\n", bfwin, action,
1141 			  gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)), bflang,
1142 			  bflang ? bflang->name : "not set");
1143 	if (!bflang)
1144 		return;
1145 	if (gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)) && bfwin->current_document) {
1146 		Tbflang *tmpbflang;
1147 		const gchar *oldmime =
1148 			g_file_info_get_attribute_string(doc->fileinfo, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
1149 		DEBUG_MSG("lang_mode_menu_activate, got 'standard_content_type' %s from fileinfo %p\n", oldmime,
1150 				  doc->fileinfo);
1151 		if (!oldmime) {
1152 			oldmime =
1153 				g_file_info_get_attribute_string(doc->fileinfo, G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE);
1154 			DEBUG_MSG("lang_mode_menu_activate, got 'fast_content_type' %s\n", oldmime);
1155 		}
1156 		if (doc->uri && oldmime && strchr(oldmime, '?') == NULL) {
1157 			gchar *curi = NULL;
1158 			curi = g_file_get_uri(doc->uri);
1159 			tmpbflang = langmgr_get_bflang(oldmime, NULL);
1160 
1161 			DEBUG_MSG("lang_mode_menu_activate, got %p for tmpbflang with name %s\n", tmpbflang,
1162 					  tmpbflang->name);
1163 
1164 			if (!tmpbflang && g_strcmp0(oldmime, "application/octet-stream") != 0) {
1165 				/* ask the user to register oldmime for the chosen language */
1166 				ask_register_custom_mime_for_bflang(bfwin, bflang, oldmime);
1167 			} else {
1168 				gchar *key = mime_with_extension(oldmime, curi);
1169 				ask_register_custom_mime_for_bflang(bfwin, bflang, key);
1170 				g_free(key);
1171 			}
1172 			g_free(curi);
1173 		}
1174 
1175 		doc_set_mimetype(bfwin->current_document, bflang->mimetypes->data, NULL);
1176 	}
1177 }
1178 
1179 static void
create_single_lang_mode_menu(Tbfwin * bfwin,Tbflang * bflang,gint value,gboolean set_active,GSList ** group)1180 create_single_lang_mode_menu(Tbfwin *bfwin, Tbflang *bflang, gint value, gboolean set_active, GSList **group)
1181 {
1182 	GtkRadioAction *action;
1183 	action = gtk_radio_action_new(bflang->name, bflang->name, NULL, NULL, value);
1184 	DEBUG_MSG("bfwin_create_single_lang_mode_menu, create action %p for lang %p (%s)\n", action, bflang,bflang->name);
1185 	gtk_action_group_add_action(bfwin->lang_mode_group, GTK_ACTION(action));
1186 	gtk_radio_action_set_group(action, *group);
1187 	*group = gtk_radio_action_get_group(action);
1188 	g_object_set_data(G_OBJECT(action), "bflang", (gpointer) bflang);
1189 	gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), set_active);
1190 	g_signal_connect(G_OBJECT(action), "activate", G_CALLBACK(lang_mode_menu_activate), bfwin);
1191 	gtk_ui_manager_add_ui(bfwin->uimanager, bfwin->lang_mode_merge_id,
1192 								  "/MainMenu/DocumentMenu/DocumentLangMode/LangModePlaceholder", bflang->name,
1193 								  bflang->name, GTK_UI_MANAGER_MENUITEM, FALSE);
1194 	g_object_unref(action);
1195 }
1196 
1197 void
lang_mode_menu_create(Tbfwin * bfwin)1198 lang_mode_menu_create(Tbfwin * bfwin)
1199 {
1200 	GSList *group = NULL;
1201 	GList *list, *freelist;
1202 	gint value = 0;
1203 
1204 	if (!bfwin->uimanager)
1205 		return;
1206 
1207 	freelist = langmgr_get_languages();
1208 	DEBUG_MSG("lang_mode_menu_create, add %d languages to bfwin %p\n", g_list_length(freelist), bfwin);
1209 
1210 	if (!freelist)
1211 		return;
1212 
1213 	if (!bfwin->lang_mode_group) {
1214 		bfwin->lang_mode_group = gtk_action_group_new("LangModeActions");
1215 		gtk_ui_manager_insert_action_group(bfwin->uimanager, bfwin->lang_mode_group, 1);
1216 	} else {
1217 		dynamic_menu_empty(bfwin->uimanager, bfwin->lang_mode_merge_id, bfwin->lang_mode_group);
1218 	}
1219 
1220 	bfwin->lang_mode_merge_id = gtk_ui_manager_new_merge_id(bfwin->uimanager);
1221 	for (list = g_list_first(freelist); list; list = list->next) {
1222 		Tbflang *bflang = (Tbflang *) list->data;
1223 		if (bflang->in_menu) {
1224 			create_single_lang_mode_menu(bfwin, bflang, value, bfwin->current_document
1225 				&& BLUEFISH_TEXT_VIEW(bfwin->current_document->view)->bflang == bflang, &group);
1226 			value++;
1227 		}
1228 	}
1229 	g_list_free(freelist);
1230 }
1231 
1232 
1233 
1234 void
bfwin_main_ui_init(Tbfwin * bfwin,GtkWidget * vbox)1235 bfwin_main_ui_init(Tbfwin * bfwin, GtkWidget * vbox)
1236 {
1237 	GtkActionGroup *action_group;
1238 	GtkUIManager *manager;
1239 	guint merge_id = 0;
1240 	GtkWidget *toolbar;
1241 	GError *error = NULL;
1242 
1243 	manager = bfwin->uimanager;
1244 
1245 	gtk_window_add_accel_group(GTK_WINDOW(bfwin->main_window), gtk_ui_manager_get_accel_group(manager));
1246 
1247 	action_group = gtk_action_group_new("topLevelMenus");
1248 	gtk_action_group_set_translation_domain(action_group, GETTEXT_PACKAGE);
1249 	gtk_action_group_add_actions(action_group, top_level_menus, G_N_ELEMENTS(top_level_menus), bfwin);
1250 	gtk_ui_manager_insert_action_group(manager, action_group, 0);
1251 	g_object_unref(action_group);
1252 
1253 	action_group = gtk_action_group_new("GlobalActions");
1254 	gtk_action_group_set_translation_domain(action_group, GETTEXT_PACKAGE);
1255 	gtk_action_group_add_actions(action_group, global_actions, G_N_ELEMENTS(global_actions), bfwin);
1256 	gtk_action_group_add_toggle_actions(action_group, global_toggle_actions,
1257 										G_N_ELEMENTS(global_toggle_actions), bfwin);
1258 	gtk_ui_manager_insert_action_group(manager, action_group, 0);
1259 	g_object_unref(action_group);
1260 	bfwin->globalGroup = action_group;
1261 
1262 	action_group = gtk_action_group_new("DocumentActions");
1263 	gtk_action_group_set_translation_domain(action_group, GETTEXT_PACKAGE);
1264 	gtk_action_group_add_actions(action_group, document_actions, G_N_ELEMENTS(document_actions), bfwin);
1265 	gtk_ui_manager_insert_action_group(manager, action_group, 0);
1266 	g_object_unref(action_group);
1267 	bfwin->documentGroup = action_group;
1268 
1269 	action_group = gtk_action_group_new("EditActions");
1270 	gtk_action_group_set_translation_domain(action_group, GETTEXT_PACKAGE);
1271 	gtk_action_group_add_actions(action_group, edit_actions, G_N_ELEMENTS(edit_actions), bfwin);
1272 	gtk_ui_manager_insert_action_group(manager, action_group, 0);
1273 	g_object_unref(action_group);
1274 	bfwin->editGroup = action_group;
1275 
1276 	action_group = gtk_action_group_new("FindReplaceActions");
1277 	gtk_action_group_set_translation_domain(action_group, GETTEXT_PACKAGE);
1278 	gtk_action_group_add_actions(action_group, find_replace_actions, G_N_ELEMENTS(find_replace_actions),
1279 								 bfwin);
1280 	gtk_ui_manager_insert_action_group(manager, action_group, 0);
1281 	g_object_unref(action_group);
1282 	bfwin->findReplaceGroup = action_group;
1283 
1284 	action_group = gtk_action_group_new("UndoRedoActions");
1285 	gtk_action_group_set_translation_domain(action_group, GETTEXT_PACKAGE);
1286 	gtk_action_group_add_actions(action_group, undo_redo_actions, G_N_ELEMENTS(undo_redo_actions), bfwin);
1287 	gtk_ui_manager_insert_action_group(manager, action_group, 0);
1288 	g_object_unref(action_group);
1289 	bfwin->undoGroup = action_group;
1290 
1291 	action_group = gtk_action_group_new("ProjectActions");
1292 	gtk_action_group_set_translation_domain(action_group, GETTEXT_PACKAGE);
1293 	gtk_action_group_add_actions(action_group, project_actions, G_N_ELEMENTS(project_actions), bfwin);
1294 	gtk_ui_manager_insert_action_group(manager, action_group, 0);
1295 	g_object_unref(action_group);
1296 	bfwin->projectGroup = action_group;
1297 	/*g_print("loading UI from %s\n",MAIN_MENU_UI); */
1298 	gtk_ui_manager_add_ui_from_file(manager, MAIN_MENU_UI, &error);
1299 	if (error != NULL) {
1300 		g_warning("building main menu failed: %s", error->message);
1301 		g_error_free(error);
1302 	}
1303 #ifndef WIN32
1304 #ifndef MAC_INTEGRATION
1305 	GtkAction *action = gtk_action_new("FileOpenURL", _("Open _URL..."), NULL, NULL);
1306 	gtk_action_group_add_action(bfwin->globalGroup, action);
1307 	g_signal_connect(G_OBJECT(action), "activate", G_CALLBACK(file_open_url_cb), bfwin);
1308 
1309 	merge_id = gtk_ui_manager_new_merge_id(manager);
1310 	gtk_ui_manager_add_ui(manager, merge_id,
1311 						  "/MainMenu/FileMenu/OpenURLPlaceholder", "FileOpenURL",
1312 						  "FileOpenURL", GTK_UI_MANAGER_MENUITEM, TRUE);
1313 	g_object_unref(action);
1314 
1315 	action = gtk_action_new("FileUploadDownload", _("Upload _/ Download..."), NULL, NULL);
1316 	gtk_action_group_add_action(bfwin->globalGroup, action);
1317 	g_signal_connect(G_OBJECT(action), "activate", G_CALLBACK(ui_upload_download_dialog), bfwin);
1318 
1319 	merge_id = gtk_ui_manager_new_merge_id(manager);
1320 	gtk_ui_manager_add_ui(manager, merge_id,
1321 						  "/MainMenu/FileMenu/UploadDownloadPlaceholder", "FileUploadDownload",
1322 						  "FileUploadDownload", GTK_UI_MANAGER_MENUITEM, TRUE);
1323 	g_object_unref(action);
1324 #endif							/* MAC_INTEGRATION */
1325 #endif							/* WIN32 */
1326 
1327 #ifdef HAVE_LIBENCHANT
1328 	GtkToggleAction *toggleaction = gtk_toggle_action_new("SpellCheck", _("_Spell Check"), NULL, NULL);
1329 	gtk_action_group_add_action(bfwin->documentGroup, GTK_ACTION(toggleaction));
1330 	g_signal_connect(G_OBJECT(toggleaction), "activate", G_CALLBACK(ui_set_spell_check), bfwin);
1331 
1332 	merge_id = gtk_ui_manager_new_merge_id(manager);
1333 	gtk_ui_manager_add_ui(manager, merge_id,
1334 						  "/MainMenu/DocumentMenu/SpellCheckPlaceholder", "SpellCheck",
1335 						  "SpellCheck", GTK_UI_MANAGER_MENUITEM, TRUE);
1336 	g_object_unref(toggleaction);
1337 #endif
1338 
1339 	bfwin->menubar = gtk_ui_manager_get_widget(manager, "/MainMenu");
1340 #if GTK_CHECK_VERSION(3,4,0)
1341 	gtk_container_add(GTK_CONTAINER(vbox), bfwin->menubar);
1342 #else
1343 	gtk_box_pack_start(GTK_BOX(vbox), bfwin->menubar, FALSE, FALSE, 0);
1344 #endif
1345 	gtk_widget_show(bfwin->menubar);
1346 
1347 	bfwin_templates_menu_create(bfwin);
1348 	bfwin_encodings_menu_create(bfwin);
1349 	DEBUG_MSG("bfwin_main_ui_init, call lang_mode_menu_create(bfwin=%p)\n", bfwin);
1350 	lang_mode_menu_create(bfwin);
1351 	bfwin_commands_menu_create(bfwin);
1352 	bfwin_filters_menu_create(bfwin);
1353 	bfwin_outputbox_menu_create(bfwin);
1354 	bfwin_recent_menu_create(bfwin, FALSE);
1355 
1356 	set_project_menu_actions(bfwin, FALSE);
1357 
1358 	bfwin_set_menu_toggle_item_from_path(bfwin->uimanager, "/MainMenu/ViewMenu/ViewSidePane",
1359 										 bfwin->session->view_left_panel);
1360 	bfwin_set_menu_toggle_item_from_path(bfwin->uimanager, "/MainMenu/ViewMenu/ViewMainToolbar",
1361 										 bfwin->session->view_main_toolbar);
1362 	bfwin_set_menu_toggle_item_from_path(bfwin->uimanager, "/MainMenu/ViewMenu/ViewStatusbar",
1363 										 bfwin->session->view_statusbar);
1364 
1365 	/* now the toolbars */
1366 #if GTK_CHECK_VERSION(3,4,0)
1367 	bfwin->main_toolbar_hb = gtk_grid_new();
1368 	gtk_orientable_set_orientation(GTK_ORIENTABLE(bfwin->main_toolbar_hb), GTK_ORIENTATION_HORIZONTAL);
1369 	gtk_container_add(GTK_CONTAINER(bfwin->toolbarbox), bfwin->main_toolbar_hb);
1370 #else
1371 	bfwin->main_toolbar_hb = gtk_handle_box_new();
1372 	gtk_box_pack_start(GTK_BOX(bfwin->toolbarbox), bfwin->main_toolbar_hb, TRUE, FALSE, 0);
1373 #endif
1374 
1375 /* looks like this is dead code
1376 	gtk_box_pack_start(GTK_BOX(bfwin->toolbarbox), bfwin->html_toolbar_hb, FALSE, FALSE, 0); */
1377 
1378 	toolbar = gtk_ui_manager_get_widget(manager, "/MainToolbar");
1379 	gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
1380 	gtk_toolbar_set_icon_size(GTK_TOOLBAR(toolbar), GTK_ICON_SIZE_LARGE_TOOLBAR);
1381 #if GTK_CHECK_VERSION(3,4,0)
1382 	/* This shouldn't be necessary, but work around a sizing issue when using GtkGrid */
1383 	gtk_toolbar_set_show_arrow(GTK_TOOLBAR(toolbar), FALSE);
1384 	gtk_widget_set_hexpand(GTK_WIDGET(toolbar), TRUE);
1385 #endif
1386 	gtk_container_add(GTK_CONTAINER(bfwin->main_toolbar_hb), toolbar);
1387 
1388 	gtk_widget_show(toolbar);
1389 }
1390 
1391 void
bfwin_set_undo_redo_actions(Tbfwin * bfwin,gboolean undo,gboolean redo)1392 bfwin_set_undo_redo_actions(Tbfwin * bfwin, gboolean undo, gboolean redo)
1393 {
1394 	GtkUIManager *manager = bfwin->uimanager;
1395 
1396 	bfwin_action_set_sensitive(manager, "/MainMenu/EditMenu/Undo", undo);
1397 	bfwin_action_set_sensitive(manager, "/MainMenu/EditMenu/UndoAll", undo);
1398 	bfwin_action_set_sensitive(manager, "/MainMenu/EditMenu/Redo", redo);
1399 	bfwin_action_set_sensitive(manager, "/MainMenu/EditMenu/RedoAll", redo);
1400 }
1401 
1402 void
bfwin_set_cutcopypaste_actions(Tbfwin * bfwin,gboolean enabled)1403 bfwin_set_cutcopypaste_actions(Tbfwin * bfwin, gboolean enabled)
1404 {
1405 	GtkUIManager *manager = bfwin->uimanager;
1406 	bfwin_action_set_sensitive(manager, "/MainMenu/EditMenu/Cut", enabled);
1407 	bfwin_action_set_sensitive(manager, "/MainMenu/EditMenu/Copy", enabled);
1408 	bfwin_action_set_sensitive(manager, "/MainMenu/EditMenu/Paste", enabled);
1409 	bfwin_action_set_sensitive(manager, "/MainMenu/EditMenu/PasteSpecial", enabled);
1410 	bfwin_action_set_sensitive(manager, "/MainMenu/EditMenu/EditSelectAll", enabled);
1411 }
1412 
1413 
1414 
1415 void
bfwin_set_document_menu_items(Tdocument * doc)1416 bfwin_set_document_menu_items(Tdocument * doc)
1417 {
1418 	GtkUIManager *manager = BFWIN(doc->bfwin)->uimanager;
1419 
1420 	bfwin_set_undo_redo_actions(doc->bfwin, doc_has_undo_list(doc), doc_has_redo_list(doc));
1421 
1422 	bfwin_set_menu_toggle_item_from_path(manager, "/MainMenu/DocumentMenu/AutoCompletion",
1423 										 bluefish_text_view_get_auto_complete(BLUEFISH_TEXT_VIEW(doc->view)));
1424 	bfwin_set_menu_toggle_item_from_path(manager, "/MainMenu/DocumentMenu/AutoIndent",
1425 										 bluefish_text_view_get_auto_indent(BLUEFISH_TEXT_VIEW(doc->view)));
1426 	bfwin_set_menu_toggle_item_from_path(manager, "/MainMenu/DocumentMenu/HighlightBlockDelimiters",
1427 										 bluefish_text_view_get_show_mbhl(BLUEFISH_TEXT_VIEW(doc->view)));
1428 	bfwin_set_menu_toggle_item_from_path(manager, "/MainMenu/DocumentMenu/ShowBlocks",
1429 										 bluefish_text_view_get_show_blocks(BLUEFISH_TEXT_VIEW(doc->view)));
1430 	bfwin_set_menu_toggle_item_from_path(manager, "/MainMenu/DocumentMenu/ShowLineNumbers",
1431 										 bluefish_text_view_get_show_line_numbers(BLUEFISH_TEXT_VIEW
1432 																				  (doc->view)));
1433 	bfwin_set_menu_toggle_item_from_path(manager, "/MainMenu/DocumentMenu/ShowRightMargin",
1434 										 bluefish_text_view_get_show_right_margin(BLUEFISH_TEXT_VIEW
1435 																				  (doc->view)));
1436 	bfwin_set_menu_toggle_item_from_path(manager, "/MainMenu/DocumentMenu/ShowVisibleSpacing",
1437 										 bluefish_text_view_get_show_visible_spacing(BLUEFISH_TEXT_VIEW
1438 																					 (doc->view)));
1439 	bfwin_set_menu_toggle_item_from_path(manager, "/MainMenu/DocumentMenu/ShowSplitView",
1440 										 (doc->slave != NULL));
1441 	bfwin_set_menu_toggle_item_from_path(manager, "/MainMenu/DocumentMenu/WrapText",
1442 										 gtk_text_view_get_wrap_mode(GTK_TEXT_VIEW(doc->view)) != GTK_WRAP_NONE);
1443 	bfwin_set_menu_toggle_item_from_path(manager, "/MainMenu/DocumentMenu/HighlightSyntax",
1444 										 doc->highlightstate);
1445 #ifdef HAVE_LIBENCHANT
1446 	bfwin_set_menu_toggle_item(BFWIN(doc->bfwin)->documentGroup, "SpellCheck",
1447 							   BLUEFISH_TEXT_VIEW(doc->view)->spell_check);
1448 #endif
1449 
1450 	bfwin_lang_mode_set_wo_activate(BFWIN(doc->bfwin), BLUEFISH_TEXT_VIEW(doc->view)->bflang);
1451 	bfwin_encoding_set_wo_activate(BFWIN(doc->bfwin), doc->encoding);
1452 
1453 	/* we should also disable certain menu's if the document is readonly */
1454 	bfwin_action_set_sensitive(manager, "/MainMenu/FileMenu/FileSave", !doc->readonly);
1455 	bfwin_action_set_sensitive(manager, "/MainMenu/FileMenu/FileInsert", !doc->readonly);
1456 	bfwin_action_set_sensitive(manager, "/MainMenu/FileMenu/FileRename", !doc->readonly);
1457 
1458 	bfwin_action_set_sensitive(manager, "/MainMenu/EditMenu/Cut", !doc->readonly);
1459 	bfwin_action_set_sensitive(manager, "/MainMenu/EditMenu/Paste", !doc->readonly);
1460 	bfwin_action_set_sensitive(manager, "/MainMenu/EditMenu/Replace", !doc->readonly);
1461 	/*bfwin_action_set_sensitive(manager, "/MainMenu/EditMenu/ReplaceAgain", !doc->readonly); */
1462 	bfwin_action_set_sensitive(manager, "/MainMenu/ToolsMenu/ToolsFormat/EditIndent", !doc->readonly);
1463 	bfwin_action_set_sensitive(manager, "/MainMenu/ToolsMenu/ToolsFormat/EditUnindent", !doc->readonly);
1464 }
1465 
1466 void
bfwin_action_set_sensitive(GtkUIManager * manager,const gchar * path,gboolean sensitive)1467 bfwin_action_set_sensitive(GtkUIManager * manager, const gchar * path, gboolean sensitive)
1468 {
1469 	GtkAction *action = gtk_ui_manager_get_action(manager, path);
1470 	if (!action) {
1471 		g_warning("Cannot set action sensitivity %s\n", path);
1472 		return;
1473 	}
1474 
1475 	gtk_action_set_sensitive(action, sensitive);
1476 }
1477 
1478 void
bfwin_set_menu_toggle_item(GtkActionGroup * action_group,const gchar * action_name,gboolean is_active)1479 bfwin_set_menu_toggle_item(GtkActionGroup * action_group, const gchar * action_name, gboolean is_active)
1480 {
1481 	GtkAction *action = gtk_action_group_get_action(action_group, action_name);
1482 	if (!action) {
1483 		g_warning("Cannot set-up menu action %s\n", action_name);
1484 		return;
1485 	}
1486 
1487 	if ((gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action))) != is_active)
1488 		gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), is_active);
1489 }
1490 
1491 #ifdef MAC_INTEGRATION
1492 /* Makes menu bar insensitive except for New... Open.. actions */
1493 void
bfwin_action_groups_set_sensitive(Tbfwin * bfwin,gboolean sensitive)1494 bfwin_action_groups_set_sensitive(Tbfwin * bfwin, gboolean sensitive)
1495 {
1496 	GList *tmplist;
1497 	GtkUIManager *manager = bfwin->uimanager;
1498 	GList *action_group_list = gtk_ui_manager_get_action_groups(manager);
1499 	for (tmplist = g_list_first(action_group_list); tmplist; tmplist = tmplist->next) {
1500 		const gchar *group_name = gtk_action_group_get_name(GTK_ACTION_GROUP(tmplist->data));
1501 		if (!sensitive) {
1502 			if (strcmp(group_name, "topLevelMenus") != 0
1503 				&& strcmp(group_name, "GlobalActions") != 0
1504 				&& strcmp(group_name, "AboutActions") != 0 && strcmp(group_name, "TemplateActions") != 0) {
1505 				DEBUG_MSG("setting action group sensitivity %s \n", group_name);
1506 				gtk_action_group_set_sensitive(GTK_ACTION_GROUP(tmplist->data), sensitive);
1507 			}
1508 		} else {
1509 			DEBUG_MSG("setting action group sensitivity %s \n", group_name);
1510 			gtk_action_group_set_sensitive(GTK_ACTION_GROUP(tmplist->data), sensitive);
1511 		}
1512 	}
1513 
1514 /*	Disable actions that should not be there in suspended mode on OSX */
1515 	bfwin_action_set_sensitive(manager, "/MainMenu/ViewMenu", sensitive);
1516 	bfwin_action_set_sensitive(manager, "/MainMenu/DocumentMenu", sensitive);
1517 	bfwin_action_set_sensitive(manager, "/MainMenu/ToolsMenu", sensitive);
1518 	bfwin_action_set_sensitive(manager, "/MainMenu/EditMenu", sensitive);
1519 	bfwin_action_set_sensitive(manager, "/MainMenu/FileMenu/FileNewWindow", sensitive);
1520 	bfwin_action_set_sensitive(manager, "/MainMenu/FileMenu/FileOpenSelection", sensitive);
1521 	bfwin_action_set_sensitive(manager, "/MainMenu/FileMenu/FileInsert", sensitive);
1522 	bfwin_action_set_sensitive(manager, "/MainMenu/FileMenu/FilePrint", sensitive);
1523 	bfwin_action_set_sensitive(manager, "/MainMenu/FileMenu/FileCloseWindow", sensitive);
1524 }
1525 
1526 /* Returns whether action group is available in menu bar */
1527 gboolean
bfwin_action_group_is_available(GtkUIManager * manager,gchar * action_group_name)1528 bfwin_action_group_is_available(GtkUIManager * manager, gchar * action_group_name)
1529 {
1530 	GList *tmplist;
1531 	gboolean retval = FALSE;
1532 	GList *action_group_list = gtk_ui_manager_get_action_groups(manager);
1533 	for (tmplist = g_list_first(action_group_list); tmplist; tmplist = tmplist->next) {
1534 		const gchar *group_name = gtk_action_group_get_name(GTK_ACTION_GROUP(tmplist->data));
1535 		if (strcmp(group_name, action_group_name) == 0) {
1536 			retval = TRUE;
1537 			break;
1538 		}
1539 	}
1540 	return retval;
1541 }
1542 #endif
1543 
1544 void
bfwin_set_menu_toggle_item_from_path(GtkUIManager * manager,const gchar * path,gboolean is_active)1545 bfwin_set_menu_toggle_item_from_path(GtkUIManager * manager, const gchar * path, gboolean is_active)
1546 {
1547 	GtkAction *action = gtk_ui_manager_get_action(manager, path);
1548 	if (!action) {
1549 		g_warning("Cannot set-up menu action %s\n", path);
1550 		return;
1551 	}
1552 
1553 	if ((gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action))) != is_active)
1554 		gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), is_active);
1555 }
1556 
1557 static void
dynamic_menu_item_create(GtkUIManager * uimanager,GtkActionGroup * action_group,guint merge_id,const gchar * path,const gchar * action_name,const gchar * action_label,gint radio_value,GSList ** radio_group,GCallback callback,gpointer callbackdata,gpointer actiondata)1558 dynamic_menu_item_create(GtkUIManager * uimanager, GtkActionGroup * action_group,
1559 						 guint merge_id, const gchar * path,
1560 						 const gchar * action_name, const gchar * action_label,
1561 						 gint radio_value /* -1 for non-radio-item */ , GSList ** radio_group,
1562 						 GCallback callback, gpointer callbackdata, gpointer actiondata)
1563 {
1564 	GtkAction *action;
1565 	/* avoid duplicate actions */
1566 	action = gtk_action_group_get_action(action_group, action_name);
1567 	if (action) {
1568 		g_warning("duplicate action %s, ignoring\n", action_name);
1569 		return;
1570 	}
1571 
1572 	if (radio_value == -1) {
1573 		action = gtk_action_new(action_name, action_label, NULL, NULL);
1574 	} else {
1575 		action = (GtkAction *) gtk_radio_action_new(action_name, action_label, NULL, NULL, radio_value);
1576 	}
1577 	if (!action)
1578 		return;
1579 	if (radio_value != -1 && radio_group) {
1580 		gtk_radio_action_set_group(GTK_RADIO_ACTION(action), *radio_group);
1581 		*radio_group = gtk_radio_action_get_group(GTK_RADIO_ACTION(action));
1582 	}
1583 
1584 /*	gtk_action_group_add_action(action_group, action);*/
1585 	gtk_action_group_add_action_with_accel(action_group, action, "");
1586 	g_object_set_data(G_OBJECT(action), "adata", actiondata);
1587 	g_signal_connect(G_OBJECT(action), "activate", callback, callbackdata);
1588 	DEBUG_MSG("dynamic_menu_item_create, add action %s at path %s\n", action_name, path);
1589 	gtk_ui_manager_add_ui(uimanager, merge_id, path, action_name, action_name, GTK_UI_MANAGER_MENUITEM, TRUE);
1590 	g_object_unref(action);
1591 }
1592 
1593 void
bfwin_encoding_set_wo_activate(Tbfwin * bfwin,const gchar * encoding)1594 bfwin_encoding_set_wo_activate(Tbfwin * bfwin, const gchar * encoding)
1595 {
1596 	/* We do case insensitive comparisons when checking to see if an encoding exists.
1597 	 * However GtkAction is case sensitive, so force all encodings upper case.
1598 	 */
1599 	gchar *temp = g_ascii_strup(encoding, -1);
1600 	GtkAction *action = gtk_action_group_get_action(bfwin->encodings_group, temp);
1601 	g_free(temp);
1602 
1603 	if (!action) {
1604 		g_warning("Cannot set menu action encoding %s\n", encoding);
1605 		return;
1606 	}
1607 
1608 	if (!gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action))) {
1609 		gpointer adata = g_object_get_data(G_OBJECT(action), "adata");
1610 		g_object_set_data(G_OBJECT(action), "adata", NULL);
1611 		gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), TRUE);
1612 		g_object_set_data(G_OBJECT(action), "adata", adata);
1613 	}
1614 }
1615 
1616 void
bfwin_lang_mode_set_wo_activate(Tbfwin * bfwin,Tbflang * bflang)1617 bfwin_lang_mode_set_wo_activate(Tbfwin * bfwin, Tbflang * bflang)
1618 {
1619 	GtkAction *action;
1620 	if (!bflang || !bfwin->lang_mode_group) {	/* At startup time doc is created faster that lang_mode_group */
1621 		DEBUG_MSG("bfwin_lang_mode_set_wo_activate, bflang=%p ????? return\n", bflang);
1622 		return;
1623 	}
1624 	action = gtk_action_group_get_action(bfwin->lang_mode_group, bflang->name);
1625 	DEBUG_MSG("bfwin_lang_mode_set_wo_activate, got action %p for bflang=%s\n", action, bflang->name);
1626 	if (!action) {
1627 		GSList *group;
1628 		/* because we hide certain languages from the menu it is perfectly fine if we cannot find an
1629 		action for a certain language file. In such a situation we have to create it. Text always exist,
1630 		so we take the group from Text */
1631 		action = gtk_action_group_get_action(bfwin->lang_mode_group,"Text");
1632 		group = gtk_radio_action_get_group(GTK_RADIO_ACTION(action));
1633 		create_single_lang_mode_menu(bfwin, bflang, -1, TRUE, &group);
1634 		return;
1635 	}
1636 
1637 	if (!gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action))) {
1638 		DEBUG_MSG("action %p was not active, so activate it!\n", action);
1639 		/*gtk_action_block_activate(action); this only blocks a direct call to gtk_action_activate, not a set_active() */
1640 		g_object_set_data(G_OBJECT(action), "bflang", (gpointer) NULL);
1641 		gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), TRUE);
1642 		g_object_set_data(G_OBJECT(action), "bflang", (gpointer) bflang);
1643 		/*gtk_action_unblock_activate(action); */
1644 	}
1645 
1646 }
1647 
1648 static void
commands_menu_activate(GtkAction * action,gpointer user_data)1649 commands_menu_activate(GtkAction * action, gpointer user_data)
1650 {
1651 	gchar **arr = g_object_get_data(G_OBJECT(action), "adata");
1652 	DEBUG_MSG("commands_menu_activate, call external_command with bfwin=%p and command_string=%s\n",
1653 			  user_data, arr[2]);
1654 	external_command(BFWIN(user_data), arr[2]);
1655 }
1656 
1657 void
bfwin_commands_menu_create(Tbfwin * bfwin)1658 bfwin_commands_menu_create(Tbfwin * bfwin)
1659 {
1660 	GList *list;
1661 
1662 	if (!bfwin->commands_group) {
1663 		bfwin->commands_group = gtk_action_group_new("CommandsActions");
1664 		gtk_ui_manager_insert_action_group(bfwin->uimanager, bfwin->commands_group, 1);
1665 	} else {
1666 		dynamic_menu_empty(bfwin->uimanager, bfwin->commands_merge_id, bfwin->commands_group);
1667 	}
1668 	bfwin->commands_merge_id = gtk_ui_manager_new_merge_id(bfwin->uimanager);
1669 	for (list = g_list_last(main_v->props.external_command); list; list = list->prev) {
1670 		gchar **arr = list->data;
1671 		/*  arr[0] = state
1672 		 *  arr[1] = name
1673 		 *  arr[2] = command
1674 		 *  arr[3] = is_default_browser
1675 		 */
1676 		if (g_strv_length(arr) == 4 && (arr[0][0] == '1' || arr[0][0] == '3')) {
1677 			if (arr[3][0] == '1') {
1678 				dynamic_menu_item_create(bfwin->uimanager, bfwin->commands_group, bfwin->commands_merge_id,
1679 										 "/MainMenu/ToolsMenu/DefaultBrowserPlaceholder",
1680 										 arr[1], arr[1], -1, NULL, G_CALLBACK(commands_menu_activate), bfwin,
1681 										 arr);
1682 			} else {
1683 				dynamic_menu_item_create(bfwin->uimanager, bfwin->commands_group, bfwin->commands_merge_id,
1684 										 "/MainMenu/ToolsMenu/ToolsCommands/CommandsPlaceholder",
1685 										 arr[1], arr[1], -1, NULL, G_CALLBACK(commands_menu_activate), bfwin,
1686 										 arr);
1687 			}
1688 		}
1689 	}
1690 }
1691 
1692 static void
encodings_menu_activate(GtkAction * action,gpointer user_data)1693 encodings_menu_activate(GtkAction * action, gpointer user_data)
1694 {
1695 	Tbfwin *bfwin = BFWIN(user_data);
1696 	gchar **arr;
1697 	if (!gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action))) {
1698 		return;
1699 	}
1700 	arr = g_object_get_data(G_OBJECT(action), "adata");
1701 	if (!arr)
1702 		return;
1703 
1704 	DEBUG_MSG("encodings_menu_activate, encoding=%s\n", arr[1]);
1705 	if (arr[1] && bfwin->current_document) {
1706 		if ((!bfwin->current_document->encoding || strcmp(arr[1], bfwin->current_document->encoding) != 0)) {
1707 			if (bfwin->current_document->encoding)
1708 				g_free(bfwin->current_document->encoding);
1709 			bfwin->current_document->encoding = g_strdup(arr[1]);
1710 			doc_set_tooltip(bfwin->current_document);
1711 			doc_set_statusbar_lang_encoding(bfwin->current_document);
1712 			if (main_v->props.auto_set_encoding_meta) {
1713 				update_encoding_meta_in_file(bfwin->current_document, bfwin->current_document->encoding);
1714 			}
1715 			DEBUG_MSG("encodings_menu_activate, set to %s\n", arr[1]);
1716 		}
1717 		if (bfwin->session->encoding)
1718 			g_free(bfwin->session->encoding);
1719 		bfwin->session->encoding = g_strdup(arr[1]);
1720 		DEBUG_MSG("encodings menu activate, session encoding now is %s\n", bfwin->session->encoding);
1721 	}
1722 }
1723 
1724 void
bfwin_encodings_menu_create(Tbfwin * bfwin)1725 bfwin_encodings_menu_create(Tbfwin * bfwin)
1726 {
1727 	GSList *group = NULL;
1728 	GList *list;
1729 	gint value = 0;
1730 
1731 	if (!bfwin->encodings_group) {
1732 		bfwin->encodings_group = gtk_action_group_new("EncodingsActions");
1733 		gtk_ui_manager_insert_action_group(bfwin->uimanager, bfwin->encodings_group, 1);
1734 	} else {
1735 		dynamic_menu_empty(bfwin->uimanager, bfwin->encodings_merge_id, bfwin->encodings_group);
1736 	}
1737 
1738 	bfwin->encodings_merge_id = gtk_ui_manager_new_merge_id(bfwin->uimanager);
1739 
1740 	for (list = g_list_last(main_v->globses.encodings); list; list = list->prev) {
1741 		gchar **arr = (gchar **) list->data;
1742 
1743 		if (g_strv_length(arr) == 3 && arr[2][0] == '1') {
1744 			gchar *label = g_strdup_printf("%s (%s)", arr[0], arr[1]);
1745 			dynamic_menu_item_create(bfwin->uimanager, bfwin->encodings_group, bfwin->encodings_merge_id,
1746 									 "/MainMenu/DocumentMenu/DocumentEncoding/EncodingPlaceholder",
1747 									 arr[1], label, value, &group, G_CALLBACK(encodings_menu_activate), bfwin,
1748 									 arr);
1749 			g_free(label);
1750 			value++;
1751 		}
1752 	}
1753 }
1754 
1755 typedef struct {
1756 	Tbfwin *bfwin;
1757 	GtkWidget *neveraskagain;
1758 	Tselectionsave *selsave;
1759 	const gchar *command;
1760 } Tfilterdialog;
1761 
1762 static void
filter_dialog_response(GtkWidget * widget,gint response_id,gpointer user_data)1763 filter_dialog_response(GtkWidget * widget, gint response_id, gpointer user_data)
1764 {
1765 	Tfilterdialog *fd = user_data;
1766 	gint begin = 0, end = -1;
1767 
1768 	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fd->neveraskagain))) {
1769 		main_v->globses.filter_on_selection_mode = (response_id == 1) ? 1 : 2;
1770 	}
1771 	gtk_widget_destroy(widget);
1772 	doc_restore_selection(fd->selsave, TRUE);	/* the restore will also free the Tselectionsave */
1773 	if (response_id == 1 && fd->bfwin->current_document)
1774 		doc_get_selection(fd->bfwin->current_document, &begin, &end);
1775 	DEBUG_MSG("filter_dialog_response, calling filter_command for %s\n", fd->command);
1776 	filter_command(fd->bfwin, fd->command, begin, end);
1777 	g_slice_free(Tfilterdialog, fd);
1778 }
1779 
1780 static void
filters_menu_activate(GtkAction * action,gpointer user_data)1781 filters_menu_activate(GtkAction * action, gpointer user_data)
1782 {
1783 	Tbfwin *bfwin = BFWIN(user_data);
1784 	gchar **arr = g_object_get_data(G_OBJECT(action), "adata");
1785 	const gchar *command = arr[2];
1786 	gint begin = 0, end = -1;
1787 	/* if we have a selection, and the filter can be used on a selection,
1788 	   we should ask if it should be the complete file or the selection */
1789 
1790 	if (main_v->globses.filter_on_selection_mode != 2 && operatable_on_selection(command)
1791 		&& bfwin->current_document && doc_has_selection(bfwin->current_document)) {
1792 		if (main_v->globses.filter_on_selection_mode == 1) {
1793 			DEBUG_MSG("filters_menu_activate, don't ask, just work on selection\n");
1794 			doc_get_selection(bfwin->current_document, &begin, &end);
1795 			filter_command(bfwin, command, begin, end);
1796 		} else {
1797 			GtkWidget *dialog, *button, *hbox;
1798 			Tfilterdialog *fd;
1799 
1800 			fd = g_slice_new(Tfilterdialog);
1801 			fd->bfwin = bfwin;
1802 			fd->command = command;
1803 
1804 			fd->selsave = doc_save_selection(bfwin->current_document);
1805 			/* TODO: this dialog is not very convenient, hitting enter should choose 'selection' */
1806 			dialog =
1807 				gtk_message_dialog_new(GTK_WINDOW(bfwin->main_window), GTK_DIALOG_DESTROY_WITH_PARENT,
1808 									   GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, _("Text area to filter"));
1809 			gtk_dialog_add_button(GTK_DIALOG(dialog), _("All text"), 0);
1810 			button = gtk_dialog_add_button(GTK_DIALOG(dialog), _("Selected text only"), 1);
1811 			gtk_widget_grab_default(button);
1812 			fd->neveraskagain = gtk_check_button_new_with_label(_("Never ask again"));
1813 			hbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1814 			gtk_box_pack_end(GTK_BOX(hbox), fd->neveraskagain, FALSE, FALSE, 4);
1815 			g_signal_connect(dialog, "response", G_CALLBACK(filter_dialog_response), fd);
1816 			gtk_widget_show_all(dialog);
1817 		}
1818 	} else {
1819 		DEBUG_MSG("filters_menu_activate, calling filter_command for %s\n", command);
1820 		filter_command(bfwin, command, begin, end);
1821 	}
1822 }
1823 
1824 void
bfwin_filters_menu_create(Tbfwin * bfwin)1825 bfwin_filters_menu_create(Tbfwin * bfwin)
1826 {
1827 	GList *list;
1828 
1829 	if (!bfwin->filters_group) {
1830 		bfwin->filters_group = gtk_action_group_new("FiltersActions");
1831 		gtk_ui_manager_insert_action_group(bfwin->uimanager, bfwin->filters_group, 1);
1832 	} else {
1833 		dynamic_menu_empty(bfwin->uimanager, bfwin->filters_merge_id, bfwin->filters_group);
1834 	}
1835 
1836 	bfwin->filters_merge_id = gtk_ui_manager_new_merge_id(bfwin->uimanager);
1837 
1838 	for (list = g_list_last(main_v->props.external_filter); list; list = list->prev) {
1839 		gchar **arr = list->data;
1840 		/* arr[0] = state
1841 		 * arr[1] = name
1842 		 * arr[2] = command
1843 		 */
1844 		if (g_strv_length(arr) == 3 && (arr[0][0] == '1' || arr[0][0] == '3')) {
1845 			dynamic_menu_item_create(bfwin->uimanager, bfwin->filters_group,
1846 									 bfwin->filters_merge_id,
1847 									 "/MainMenu/ToolsMenu/ToolsFilters/FiltersPlaceholder", arr[1], arr[1],
1848 									 -1, NULL, G_CALLBACK(filters_menu_activate), bfwin, arr);
1849 		} else {
1850 			DEBUG_MSG("bfwin_filters_menu_create, CORRUPT ENTRY IN filter actions; array count =%d\n",
1851 					  g_strv_length(arr));
1852 		}
1853 	}
1854 }
1855 
1856 static void
outputbox_menu_activate(GtkAction * action,gpointer user_data)1857 outputbox_menu_activate(GtkAction * action, gpointer user_data)
1858 {
1859 	gchar **arr = g_object_get_data(G_OBJECT(action), "adata");
1860 	DEBUG_MSG("outputbox_menu_activate, open outputbox with command %s and filter %s\n", arr[6], arr[2]);
1861 	outputbox(BFWIN(user_data), arr[2], atoi(arr[3]), atoi(arr[4]), atoi(arr[5]), arr[6]);
1862 }
1863 
1864 void
bfwin_outputbox_menu_create(Tbfwin * bfwin)1865 bfwin_outputbox_menu_create(Tbfwin * bfwin)
1866 {
1867 	GList *list;
1868 
1869 	if (!bfwin->outputbox_group) {
1870 		bfwin->outputbox_group = gtk_action_group_new("OutputboxActions");
1871 		gtk_ui_manager_insert_action_group(bfwin->uimanager, bfwin->outputbox_group, 1);
1872 	} else {
1873 		dynamic_menu_empty(bfwin->uimanager, bfwin->outputbox_merge_id, bfwin->outputbox_group);
1874 	}
1875 
1876 	bfwin->outputbox_merge_id = gtk_ui_manager_new_merge_id(bfwin->uimanager);
1877 
1878 	for (list = g_list_last(main_v->props.external_outputbox); list; list = list->prev) {
1879 		gchar **arr = list->data;
1880 		/* arr[0] = state
1881 		 * arr[1] = name
1882 		 * arr[2] = pattern
1883 		 * arr[3] = file subpattern     gint
1884 		 * arr[4] = line subpattern     gint
1885 		 * arr[5] = output subpattern   gint
1886 		 * arr[6] = command
1887 		 */
1888 		if (g_strv_length(arr) == 7 && (arr[0][0] == '1' || arr[0][0] == '3')) {
1889 			dynamic_menu_item_create(bfwin->uimanager, bfwin->outputbox_group,
1890 									 bfwin->outputbox_merge_id,
1891 									 "/MainMenu/ToolsMenu/ToolsOutputBox/OutputBoxPlaceholder", arr[1],
1892 									 arr[1], -1, NULL, G_CALLBACK(outputbox_menu_activate), bfwin, arr);
1893 		} else {
1894 			DEBUG_MSG("bfwin_outputbox_menu_create, CORRUPT ENTRY IN outputbox action; array count =%d\n",
1895 					  g_strv_length(arr));
1896 		}
1897 	}
1898 }
1899 
1900 static gchar *
recent_menu_label(const gchar * curi,GFile * uri)1901 recent_menu_label(const gchar *curi, GFile *uri)
1902 {
1903 	gchar *label = curi;
1904 	if (uri && g_file_is_native(uri)) {
1905 		label = g_file_get_path(uri);
1906 	} else if (uri && curi == NULL) {
1907 		label = g_file_get_uri(uri);
1908 	}
1909 	return label;
1910 }
1911 
1912 
1913 static void
recent_menu_remove_backend(Tbfwin * bfwin,const gchar * menupath,const gchar * label)1914 recent_menu_remove_backend(Tbfwin * bfwin, const gchar * menupath, const gchar * label)
1915 {
1916 	GtkWidget *menuitem, *menu;
1917 	GList *list, *tmplist;
1918 
1919 	menuitem = gtk_ui_manager_get_widget(bfwin->uimanager, menupath);
1920 	menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menuitem));
1921 	list = gtk_container_get_children(GTK_CONTAINER(menu));
1922 	DEBUG_MSG("recent_menu_remove_backend, remove item with label %s from menupath %s\n",label,menupath);
1923 	for (tmplist = list; tmplist; tmplist = tmplist->next) {
1924 		if (g_strcmp0(gtk_menu_item_get_label(tmplist->data), label) == 0) {
1925 			gtk_widget_destroy(tmplist->data);
1926 			break;
1927 		}
1928 	}
1929 	g_list_free(list);
1930 }
1931 
1932 void
bfwin_recent_menu_remove(Tbfwin * bfwin,gboolean project,const gchar * curi,GFile * uri)1933 bfwin_recent_menu_remove(Tbfwin * bfwin, gboolean project, const gchar * curi, GFile *uri)
1934 {
1935 	GList *tmplist;
1936 	gchar *label;
1937 	DEBUG_MSG("bfwin_recent_menu_remove curi=%s\n",curi);
1938 	label = recent_menu_label(curi, uri);
1939 	if (!project && bfwin->session != main_v->session) {
1940 		recent_menu_remove_backend(bfwin, "/MainMenu/FileMenu/FileOpenRecent", label);
1941 		return;
1942 	}
1943 	for (tmplist = g_list_first(main_v->bfwinlist); tmplist; tmplist = g_list_next(tmplist)) {
1944 		if (project || BFWIN(tmplist->data)->session == main_v->session) {
1945 			recent_menu_remove_backend(bfwin,
1946 									   project ? "/MainMenu/ProjectMenu/ProjectOpenRecent" :
1947 									   "/MainMenu/FileMenu/FileOpenRecent", label);
1948 		}
1949 	}
1950 	if (label != curi) {
1951 		g_free(label);
1952 	}
1953 }
1954 
1955 static void
recent_menu_activate(GtkMenuItem * menuitem,gpointer user_data)1956 recent_menu_activate(GtkMenuItem * menuitem, gpointer user_data)
1957 {
1958 	Tbfwin *bfwin = BFWIN(user_data);
1959 	GFile *uri;
1960 	const gchar *str = gtk_menu_item_get_label(menuitem);
1961 	gint len = strlen(str);
1962 	if (str[0]=='/') {
1963 		uri = g_file_new_for_path(str);
1964 	} else {
1965 		uri = g_file_new_for_uri(str);
1966 	}
1967 	if (g_strcmp0(str + len - 10, ".bfproject") == 0) {
1968 		gint status = project_open_from_file(bfwin, uri);
1969 		if (status == 0) {
1970 			gint retval = project_not_found_dialog(bfwin, uri);
1971 			switch (retval) {
1972 			case 0:
1973 				remove_filename_from_recentlist(bfwin, TRUE, uri);
1974 				break;
1975 			case 1:
1976 				remove_filename_from_recentlist(bfwin, TRUE, uri);
1977 				project_open(bfwin);
1978 				break;
1979 			}
1980 		}
1981 	} else {
1982 		doc_new_from_uri(bfwin, uri, NULL, FALSE, FALSE, -1, -1, -1, TRUE, FALSE);
1983 	}
1984 	g_object_unref(uri);
1985 }
1986 
1987 static void
recent_menu_add(Tbfwin * bfwin,GtkMenu * menu,const gchar * label)1988 recent_menu_add(Tbfwin * bfwin, GtkMenu * menu, const gchar * label)
1989 {
1990 	GtkWidget *menuitem;
1991 	menuitem = gtk_menu_item_new_with_label(label);
1992 	g_signal_connect(menuitem, "activate", G_CALLBACK(recent_menu_activate), bfwin);
1993 	gtk_menu_shell_insert(GTK_MENU_SHELL(menu), menuitem, 1);
1994 	gtk_widget_show(menuitem);
1995 }
1996 
1997 static void
recent_menu_add_backend(Tbfwin * bfwin,const gchar * menupath,const gchar * curi,GFile * uri)1998 recent_menu_add_backend(Tbfwin * bfwin, const gchar * menupath, const gchar * curi, GFile *uri)
1999 {
2000 	GtkWidget *menuitem, *menu;
2001 	GList *tmplist, *list;
2002 	gchar *label=curi;
2003 	gint num = 0;
2004 	menuitem = gtk_ui_manager_get_widget(bfwin->uimanager, menupath);
2005 	menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menuitem));
2006 
2007 	label = recent_menu_label(curi, uri);
2008 
2009 	/* avoid duplicate entries,
2010 	   if recent_means_recently_closed==1 this is not essential, because
2011 	   removing from the menu is done when the file is opened, and adding only
2012 	   during close.
2013 
2014 	   if recent_means_recently_closed==0 this is essential because the file is
2015 	   actually added to the menu during opening */
2016 	recent_menu_remove_backend(bfwin, menupath, label);
2017 
2018 	recent_menu_add(bfwin, GTK_MENU(menu), label);
2019 
2020 	list = gtk_container_get_children(GTK_CONTAINER(menu));
2021 	for (tmplist = list; tmplist; tmplist = tmplist->next) {
2022 		if (num > main_v->props.max_recent_files) {
2023 			gtk_widget_destroy(tmplist->data);
2024 		}
2025 		num++;
2026 	}
2027 	g_list_free(list);
2028 
2029 	if (curi != label) {
2030 		g_free(label);
2031 	}
2032 }
2033 
2034 void
bfwin_recent_menu_add(Tbfwin * bfwin,gboolean project,const gchar * curi,GFile * uri)2035 bfwin_recent_menu_add(Tbfwin * bfwin, gboolean project, const gchar * curi, GFile *uri)
2036 {
2037 	GList *tmplist;
2038 	if (!project && bfwin->session != main_v->session) {
2039 		recent_menu_add_backend(bfwin, "/MainMenu/FileMenu/FileOpenRecent", curi, uri);
2040 		return;
2041 	}
2042 	for (tmplist = g_list_first(main_v->bfwinlist); tmplist; tmplist = g_list_next(tmplist)) {
2043 		if (project || BFWIN(tmplist->data)->session == main_v->session) {
2044 			recent_menu_add_backend(tmplist->data,
2045 									project ? "/MainMenu/ProjectMenu/ProjectOpenRecent" :
2046 									"/MainMenu/FileMenu/FileOpenRecent", curi, uri);
2047 		}
2048 	}
2049 
2050 }
2051 
2052 static void
recent_create_backend(Tbfwin * bfwin,const gchar * menupath,GList * recentlist)2053 recent_create_backend(Tbfwin * bfwin, const gchar * menupath, GList * recentlist)
2054 {
2055 	GtkWidget *menuitem, *menu;
2056 	GList *list, *tmplist;
2057 	gint num = 0;
2058 
2059 	menuitem = gtk_ui_manager_get_widget(bfwin->uimanager, menupath);
2060 	menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menuitem));
2061 	list = gtk_container_get_children(GTK_CONTAINER(menu));
2062 	for (tmplist = list; tmplist; tmplist = tmplist->next) {
2063 		const gchar *label = gtk_menu_item_get_label(tmplist->data);
2064 		/* don't remove the tearoff item which has an empty string as label */
2065 		if (label && label[0]) {
2066 			gtk_widget_destroy(tmplist->data);
2067 		}
2068 	}
2069 	g_list_free(list);
2070 	tmplist = g_list_nth(recentlist, main_v->props.max_recent_files);
2071 	if (!tmplist)
2072 		tmplist = g_list_last(recentlist);
2073 	for (; tmplist; tmplist = tmplist->prev) {
2074 		gchar *label = (gchar *) tmplist->data;
2075 		GFile *uri = NULL;
2076 		if (g_ascii_strncasecmp("file://", label, 7)==0) {
2077 			uri = g_file_new_for_uri(label);
2078 			label = recent_menu_label(label, uri);
2079 		}
2080 		/* recent_menu_add adds from the top, so the last item added will be on top */
2081 		recent_menu_add(bfwin, GTK_MENU(menu), label);
2082 		if (label != tmplist->data) {
2083 			g_free(label);
2084 		}
2085 		if (uri) {
2086 			g_object_unref(uri);
2087 		}
2088 		num++;
2089 	}
2090 	gtk_widget_show_all(menuitem);
2091 }
2092 
2093 void
bfwin_recent_menu_create(Tbfwin * bfwin,gboolean only_update_session)2094 bfwin_recent_menu_create(Tbfwin * bfwin, gboolean only_update_session)
2095 {
2096 	DEBUG_MSG("bfwin_recent_menu_create, only_update_session=%d\n", only_update_session);
2097 	recent_create_backend(bfwin, "/MainMenu/FileMenu/FileOpenRecent", bfwin->session->recent_files);
2098 	if (!only_update_session)
2099 		recent_create_backend(bfwin, "/MainMenu/ProjectMenu/ProjectOpenRecent",
2100 							  main_v->globses.recent_projects);
2101 }
2102 
2103 static void
templates_menu_activate(GtkAction * action,gpointer user_data)2104 templates_menu_activate(GtkAction * action, gpointer user_data)
2105 {
2106 	Tbfwin *bfwin = BFWIN(user_data);
2107 	gchar **arr = g_object_get_data(G_OBJECT(action), "adata");
2108 	GFile *uri = g_file_new_for_commandline_arg(arr[1]);
2109 	doc_new_with_template(bfwin, uri, FALSE);
2110 	g_object_unref(uri);
2111 }
2112 
2113 void
bfwin_templates_menu_create(Tbfwin * bfwin)2114 bfwin_templates_menu_create(Tbfwin * bfwin)
2115 {
2116 	GList *list;
2117 
2118 	if (!bfwin->templates_group) {
2119 		bfwin->templates_group = gtk_action_group_new("TemplateActions");
2120 		gtk_ui_manager_insert_action_group(bfwin->uimanager, bfwin->templates_group, 1);
2121 	} else {
2122 		dynamic_menu_empty(bfwin->uimanager, bfwin->templates_merge_id, bfwin->templates_group);
2123 	}
2124 	bfwin->templates_merge_id = gtk_ui_manager_new_merge_id(bfwin->uimanager);
2125 
2126 	for (list = g_list_last(main_v->templates); list; list = list->prev) {
2127 		gchar **arr = (gchar **) list->data;
2128 		if (arr && arr[0] && arr[1]) {
2129 			gchar *action_name = g_strconcat("template ", arr[0], NULL);
2130 			dynamic_menu_item_create(bfwin->uimanager, bfwin->templates_group,
2131 									 bfwin->templates_merge_id,
2132 									 "/MainMenu/FileMenu/NewFromTemplate/TemplatePlaceholder", action_name,
2133 									 arr[0], -1, NULL, G_CALLBACK(templates_menu_activate), bfwin, arr);
2134 			g_free(action_name);
2135 		}
2136 	}
2137 }
2138