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