1 /*
2  * Xiphos Bible Study Tool
3  * tabbed_browser.c - functions to facilitate tabbed browsing of different passages at once
4  *
5  * Copyright (C) 2000-2020 Xiphos Developer Team
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 2 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 Library 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, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 
26 #include <unistd.h>
27 #include <gtk/gtk.h>
28 #include <glib.h>
29 #include <glib/gstdio.h>
30 #include <libxml/tree.h>
31 #include <libxml/parser.h>
32 
33 #include "editor/slib-editor.h"
34 
35 #include "gui/xiphos.h"
36 #include "gui/tabbed_browser.h"
37 #include "gui/bibletext.h"
38 #include "gui/bibletext_dialog.h"
39 #include "gui/commentary.h"
40 #include "gui/sidebar.h"
41 #include "gui/cipher_key_dialog.h"
42 #include "gui/main_menu.h"
43 #include "gui/main_window.h"
44 #include "gui/parallel_tab.h"
45 #include "gui/dialog.h"
46 #include "gui/font_dialog.h"
47 #include "gui/dictlex.h"
48 #include "gui/widgets.h"
49 #include "gui/utilities.h"
50 
51 #include "main/lists.h"
52 #include "main/navbar_versekey.h"
53 #include "main/settings.h"
54 #include "main/sword.h"
55 #include "main/tab_history.h"
56 #include "main/xml.h"
57 
58 #include <glib/gstdio.h>
59 
60 #include "gui/debug_glib_null.h"
61 
62 static GtkWidget *tab_widget_new(PASSAGE_TAB_INFO *tbinf,
63 				 const gchar *label_text);
64 void notebook_main_add_page(PASSAGE_TAB_INFO *tbinf);
65 void set_current_tab(PASSAGE_TAB_INFO *pt);
66 
67 gboolean stop_refresh = FALSE;
68 gboolean change_tabs_no_redisplay = FALSE;
69 gboolean closing_tab = FALSE;
70 
71 GList *passage_list;
72 
73 /******************************************************************************
74  * externs
75  */
76 
77 extern gboolean sync_on;
78 //extern gboolean gsI_isrunning;
79 PASSAGE_TAB_INFO *cur_passage_tab;
80 
81 /******************************************************************************
82  * globals to this file only
83  */
84 static gboolean page_change = FALSE;
85 static gint removed_page;
86 static const gchar *default_tab_filename = ".last_session_tabs";
87 static const gchar *no_tab_filename = ".last_session_no_tabs";
88 
yes_no2true_false(const gchar * yes_no)89 static int yes_no2true_false(const gchar *yes_no)
90 {
91 	return (yes_no && !strcmp(yes_no, "yes"));
92 }
93 
true_false2yes_no(int true_false)94 static gchar *true_false2yes_no(int true_false)
95 {
96 	return (true_false ? "yes" : "no");
97 }
98 
99 /******************************************************************************
100  * Name
101  *  gui_recompute_shows
102  *
103  * Synopsis
104  *   #include "tabbed_browser.h"
105  *
106  *   void gui_recompute_shows(void)
107  *
108  * Description
109  *   a new set of text/preview/comm/dict showings has been selected.
110  *   re-align the displayed world with that.
111  *
112  * Return value
113  *   void
114  */
gui_recompute_shows(gboolean flush)115 void gui_recompute_shows(gboolean flush)
116 {
117 	if (stop_refresh)
118 		return;
119 	stop_refresh = TRUE;
120 
121 	if (flush)
122 		main_flush_widgets_content();
123 
124 	if (cur_passage_tab)
125 		gui_reassign_strdup(&settings.currentverse,
126 				    cur_passage_tab->text_commentary_key);
127 
128 	gui_show_hide_preview(settings.showpreview);
129 	gui_show_hide_texts(settings.showtexts);
130 	gui_show_hide_dicts(settings.showdicts);
131 	gui_show_hide_comms(settings.showcomms);
132 	gui_set_bible_comm_layout();
133 
134 	sync_windows();
135 
136 	stop_refresh = FALSE;
137 }
138 
139 /******************************************************************************
140  * Name
141  *  gui_recompute_view_menu_choices
142  *
143  * Synopsis
144  *   #include "tabbed_browser.h"
145  *
146  *   void gui_recompute_view_menu_choices(void)
147  *
148  * Description
149  *   formerly part of gui_recompute_shows, but moved here to keep from
150  *   triggering toggled signals on these items before new content is
151  *   ready to be displayed
152  *
153  * Return value
154  *   void
155  */
gui_recompute_view_menu_choices(void)156 void gui_recompute_view_menu_choices(void)
157 {
158 	change_tabs_no_redisplay = TRUE;
159 
160 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widgets.viewtexts_item),
161 				       settings.showtexts);
162 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widgets.viewcomms_item),
163 				       settings.showcomms);
164 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widgets.viewdicts_item),
165 				       settings.showdicts);
166 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widgets.viewpreview_item),
167 				       settings.showpreview);
168 
169 	change_tabs_no_redisplay = FALSE;
170 }
171 
172 /******************************************************************************
173  * Name
174  *  set_current_tab
175  *
176  * Synopsis
177  *   #include "tabbed_browser.h"
178  *
179  *   void set_current_tab (PASSAGE_TAB_INFO *pt)
180  *
181  * Description
182  *   point cur_passage_tab to the current tab and turns the close button on
183  *   and off
184  *
185  * Return value
186  *   void
187  */
188 
set_current_tab(PASSAGE_TAB_INFO * pt)189 void set_current_tab(PASSAGE_TAB_INFO *pt)
190 {
191 	PASSAGE_TAB_INFO *ot = cur_passage_tab;
192 
193 	if (stop_refresh)
194 		return;
195 
196 	if (!closing_tab && ot != NULL && ot->button_close != NULL) {
197 		gtk_widget_set_sensitive(ot->button_close, FALSE);
198 	}
199 	cur_passage_tab = pt;
200 	if (pt != NULL && pt->button_close != NULL) {
201 		//main_update_tab_history_menu((PASSAGE_TAB_INFO*)pt);
202 		gtk_widget_set_sensitive(pt->button_close, TRUE);
203 
204 		/* adopt panel shows from passage tab memory. */
205 		settings.showtexts = pt->showtexts;
206 		settings.showpreview = pt->showpreview;
207 		settings.showcomms = pt->showcomms;
208 		settings.showdicts = pt->showdicts;
209 		settings.comm_showing = pt->comm_showing;
210 		gui_recompute_shows(TRUE);
211 	}
212 }
213 
214 /******************************************************************************
215  * Name
216  *  pick_tab_label
217  *
218  * Synopsis
219  *   #include "tabbed_browser.h"
220  *
221  *   void pick_tab_label(PASSAGE_TAB_INFO *pt)
222  *
223  * Description
224  *   selects a tab label based on panel shows.
225  *
226  * Return value
227  *   GString *
228  *   ** caller must free it **
229  */
230 
pick_tab_label(PASSAGE_TAB_INFO * pt)231 GString *pick_tab_label(PASSAGE_TAB_INFO *pt)
232 {
233 	GString *str = g_string_new(NULL);
234 
235 	const char *abbrev_text = main_get_abbreviation(pt->text_mod);
236 	const char *abbrev_comm =
237 	    main_get_abbreviation(pt->commentary_mod);
238 	const char *abbrev_dict = main_get_abbreviation(pt->dictlex_mod);
239 	const char *abbrev_book = main_get_abbreviation(pt->book_mod);
240 
241 	if (pt->showparallel) {
242 		g_string_printf(str, "%s", _("Parallel View"));
243 		return str;
244 	}
245 
246 	if (pt->showtexts || (pt->showcomms && pt->comm_showing)) {
247 		g_string_printf(str, "%s: %s",
248 				(pt->showtexts
249 				     ? (abbrev_text ? abbrev_text : pt->text_mod)
250 				     : (pt->commentary_mod
251 					    ? (abbrev_comm ? abbrev_comm : pt->commentary_mod)
252 					    : "[no commentary]")),
253 				pt->text_commentary_key);
254 	} else {
255 		g_string_printf(str, "%s",
256 				(pt->showcomms
257 				     ? (pt->book_mod
258 					    ? (abbrev_book ? abbrev_book : pt->book_mod)
259 					    : "[no book]")
260 				     : (pt->dictlex_mod
261 					    ? (abbrev_dict ? abbrev_dict : pt->dictlex_mod)
262 					    : "[no dict]")));
263 	}
264 	return str;
265 }
266 
267 /******************************************************************************
268  * Name
269  *  notebook_main_add_page
270  *
271  * Synopsis
272  *   #include "tabbed_browser.h"
273  *
274  *   void notebook_main_add_page(PASSAGE_TAB_INFO *tbinf)
275  *
276  * Description
277  *   adds a new page and label to the main notebook for a new scripture passage
278  *
279  * Return value
280  *   void
281  */
notebook_main_add_page(PASSAGE_TAB_INFO * tbinf)282 void notebook_main_add_page(PASSAGE_TAB_INFO *tbinf)
283 {
284 	GtkWidget *tab_widget;
285 	GtkWidget *menu_label;
286 	GString *str;
287 
288 	str = pick_tab_label(tbinf);
289 	UI_VBOX(tbinf->page_widget, FALSE, 0);
290 	if (tbinf->showparallel)
291 		widgets.parallel_tab = tbinf->page_widget;
292 	gtk_widget_show(tbinf->page_widget);
293 
294 	tab_widget = tab_widget_new(tbinf, str->str);
295 	/*gtk_notebook_insert_page(GTK_NOTEBOOK(widgets.notebook_main),
296 	   tbinf->page_widget,
297 	   tab_widget,
298 	   tbinf->showparallel ? 1 : -1); */
299 	gtk_notebook_append_page(GTK_NOTEBOOK(widgets.notebook_main),
300 				 tbinf->page_widget, tab_widget);
301 
302 	gtk_notebook_set_menu_label_text(GTK_NOTEBOOK(widgets.notebook_main),
303 					 tbinf->page_widget, str->str);
304 
305 	menu_label = gtk_label_new(str->str);
306 	gtk_notebook_set_menu_label(GTK_NOTEBOOK(widgets.notebook_main),
307 				    tbinf->page_widget, menu_label);
308 	g_string_free(str, TRUE);
309 }
310 
311 /******************************************************************************
312  * Name
313  *   gui_save_tabs
314  *
315  * Synopsis
316  *   #include "tabbed_browser.h"
317  *
318  * Description
319  *   Saves the information for the current set of tabs.
320  *
321  * Return value
322  *
323  */
324 
gui_save_tabs(const gchar * filename)325 void gui_save_tabs(const gchar *filename)
326 {
327 	xmlDocPtr xml_doc;
328 	xmlNodePtr root_node;
329 	xmlNodePtr cur_node;
330 	xmlNodePtr section_node;
331 	//      xmlAttrPtr xml_attr;
332 	//const xmlChar *xml_filename;
333 	gchar *file;
334 	GList *tmp = NULL;
335 
336 	if (NULL == filename)
337 		filename = default_tab_filename;
338 
339 	if (g_access(filename, F_OK) == 0) {
340 		/* we're done, just copy for local use that can be free'd */
341 		file = g_strdup(filename);
342 	} else {
343 		gchar *tabs_dir = g_strdup_printf("%s/tabs/", settings.gSwordDir);
344 		if (g_access(tabs_dir, F_OK) == -1) {
345 			if ((g_mkdir(tabs_dir, S_IRWXU)) == -1) {
346 				gui_generic_warning_modal(_("Can't create tabs dir."));
347 				return;
348 			}
349 		}
350 		file = g_strdup_printf("%s%s", tabs_dir, filename);
351 		g_free(tabs_dir);
352 	}
353 	//xml_filename = (const xmlChar *) file;
354 
355 	xml_doc = xmlNewDoc((const xmlChar *)"1.0");
356 
357 	if (xml_doc == NULL) {
358 		gui_generic_warning_modal("Tabs document not created successfully.");
359 		return;
360 	}
361 
362 	root_node = xmlNewNode(NULL, (const xmlChar *)"Xiphos_Tabs");
363 	//xml_attr =
364 	xmlNewProp(root_node, (const xmlChar *)"Version",
365 		   (const xmlChar *)VERSION);
366 	xmlDocSetRootElement(xml_doc, root_node);
367 
368 	section_node = xmlNewChild(root_node, NULL,
369 				   (const xmlChar *)"tabs", NULL);
370 
371 	for (tmp = g_list_first(passage_list); tmp != NULL;
372 	     tmp = g_list_next(tmp)) {
373 
374 		PASSAGE_TAB_INFO *pt = (PASSAGE_TAB_INFO *)tmp->data;
375 
376 		cur_node = xmlNewChild(section_node,
377 				       NULL, (const xmlChar *)"tab",
378 				       NULL);
379 		xmlNewProp(cur_node, (const xmlChar *)"text_mod",
380 			   (const xmlChar *)pt->text_mod);
381 		xmlNewProp(cur_node, (const xmlChar *)"commentary_mod",
382 			   (const xmlChar *)pt->commentary_mod);
383 		xmlNewProp(cur_node, (const xmlChar *)"dictlex_mod",
384 			   (const xmlChar *)pt->dictlex_mod);
385 		xmlNewProp(cur_node, (const xmlChar *)"book_mod",
386 			   (const xmlChar *)pt->book_mod);
387 		xmlNewProp(cur_node,
388 			   (const xmlChar *)"text_commentary_key",
389 			   (const xmlChar *)pt->text_commentary_key);
390 		xmlNewProp(cur_node, (const xmlChar *)"dictlex_key",
391 			   (const xmlChar *)pt->dictlex_key);
392 		xmlNewProp(cur_node, (const xmlChar *)"book_offset",
393 			   (const xmlChar *)pt->book_offset);
394 		xmlNewProp(cur_node, (const xmlChar *)"comm_showing",
395 			   (const xmlChar *)
396 			   true_false2yes_no(pt->comm_showing));
397 		xmlNewProp(cur_node, (const xmlChar *)"showtexts",
398 			   (const xmlChar *)
399 			   true_false2yes_no(pt->showtexts));
400 		xmlNewProp(cur_node, (const xmlChar *)"showpreview",
401 			   (const xmlChar *)
402 			   true_false2yes_no(pt->showpreview));
403 		xmlNewProp(cur_node, (const xmlChar *)"showcomms",
404 			   (const xmlChar *)
405 			   true_false2yes_no(pt->showcomms));
406 		xmlNewProp(cur_node, (const xmlChar *)"showdicts",
407 			   (const xmlChar *)
408 			   true_false2yes_no(pt->showdicts));
409 		xmlNewProp(cur_node, (const xmlChar *)"showparallel",
410 			   (const xmlChar *)
411 			   true_false2yes_no(pt->showparallel));
412 	}
413 	xmlSaveFormatFile(file, xml_doc, 1);
414 	g_free(file);
415 	xmlFreeDoc(xml_doc);
416 }
417 
418 /******************************************************************************
419  * Name
420  *
421  *
422  * Synopsis
423  *   #include "tabbed_browser.h"
424  *
425  *   void _save_off_tabs(const gchar *filename)
426  *
427  * Description
428  *   Saves the information for the current set of tabs.
429  *
430  * Return value
431  *
432  */
433 
_save_off_tab(const gchar * filename)434 static void _save_off_tab(const gchar *filename)
435 {
436 	xmlDocPtr xml_doc;
437 	xmlNodePtr root_node;
438 	xmlNodePtr cur_node;
439 	xmlNodePtr section_node;
440 	//xmlAttrPtr xml_attr;
441 	gchar *tabs_dir;
442 	gchar *file;
443 
444 	if (NULL == filename)
445 		filename = no_tab_filename;
446 
447 	tabs_dir = g_strdup_printf("%s/tabs/", settings.gSwordDir);
448 
449 	if (g_access(tabs_dir, F_OK) == -1) {
450 		if ((g_mkdir(tabs_dir, S_IRWXU)) == -1) {
451 			gui_generic_warning_modal("Can't create tabs dir.");
452 			return;
453 		}
454 	}
455 	file = g_strdup_printf("%s%s", tabs_dir, filename);
456 	g_free(tabs_dir);
457 
458 	xml_doc = xmlNewDoc((const xmlChar *)"1.0");
459 
460 	if (xml_doc == NULL) {
461 		gui_generic_warning_modal("Tabs document not created successfully.");
462 		return;
463 	}
464 
465 	root_node = xmlNewNode(NULL, (const xmlChar *)"Xiphos_Tabs");
466 	//xml_attr =
467 	xmlNewProp(root_node, (const xmlChar *)"Version",
468 		   (const xmlChar *)VERSION);
469 	xmlDocSetRootElement(xml_doc, root_node);
470 
471 	section_node = xmlNewChild(root_node, NULL,
472 				   (const xmlChar *)"tabs", NULL);
473 
474 	cur_node = xmlNewChild(section_node,
475 			       NULL, (const xmlChar *)"tab", NULL);
476 	xmlNewProp(cur_node, (const xmlChar *)"text_mod",
477 		   (const xmlChar *)settings.MainWindowModule);
478 	xmlNewProp(cur_node, (const xmlChar *)"commentary_mod",
479 		   (const xmlChar *)settings.CommWindowModule);
480 	xmlNewProp(cur_node, (const xmlChar *)"dictlex_mod",
481 		   (const xmlChar *)settings.DictWindowModule);
482 	xmlNewProp(cur_node, (const xmlChar *)"book_mod",
483 		   (const xmlChar *)settings.book_mod);
484 	xmlNewProp(cur_node, (const xmlChar *)"text_commentary_key",
485 		   (const xmlChar *)settings.currentverse);
486 	xmlNewProp(cur_node, (const xmlChar *)"dictlex_key",
487 		   (const xmlChar *)settings.dictkey);
488 	xmlNewProp(cur_node, (const xmlChar *)"book_offset",
489 		   (const xmlChar *)settings.book_key);
490 	xmlNewProp(cur_node, (const xmlChar *)"comm_showing",
491 		   (const xmlChar *)
492 		   true_false2yes_no(settings.comm_showing));
493 	xmlNewProp(cur_node, (const xmlChar *)"showtexts",
494 		   (const xmlChar *)
495 		   true_false2yes_no(settings.showtexts));
496 	xmlNewProp(cur_node, (const xmlChar *)"showpreview",
497 		   (const xmlChar *)
498 		   true_false2yes_no(settings.showpreview));
499 	xmlNewProp(cur_node, (const xmlChar *)"showcomms",
500 		   (const xmlChar *)
501 		   true_false2yes_no(settings.showcomms));
502 	xmlNewProp(cur_node, (const xmlChar *)"showdicts",
503 		   (const xmlChar *)
504 		   true_false2yes_no(settings.showdicts));
505 	xmlNewProp(cur_node, (const xmlChar *)"showparallel",
506 		   (const xmlChar *)"no");
507 
508 	xmlSaveFormatFile(file, xml_doc, 1);
509 	g_free(file);
510 	xmlFreeDoc(xml_doc);
511 }
512 
513 /******************************************************************************
514  * Name
515  *   gui_load_tabs
516  *
517  * Synopsis
518  *   #include "tabbed_browser.h"
519  *
520  * Description
521  *   Load the tabs from the given file.
522  *
523  * Return value
524  *
525  */
526 
gui_load_tabs(const gchar * filename)527 void gui_load_tabs(const gchar *filename)
528 {
529 	xmlDocPtr xml_doc;
530 	xmlNodePtr tmp_node, childnode;
531 	//const xmlChar *xml_filename;
532 	gboolean error = FALSE;
533 	gboolean back_compat_need_save = FALSE;
534 	settings.showparatab = FALSE;
535 	PASSAGE_TAB_INFO *pt = NULL, *pt_first = NULL;
536 
537 	stop_refresh = TRUE;
538 
539 	if (filename == NULL) {
540 		error = TRUE;
541 	} else {
542 		gchar *file;
543 
544 		if (g_access(filename, F_OK) == 0) {
545 			/* we're done, just copy for local use that can be free'd */
546 			file = g_strdup(filename);
547 		} else {
548 			gchar *tabs_dir =
549 			    g_strdup_printf("%s/tabs/",
550 					    settings.gSwordDir);
551 			if (g_access(tabs_dir, F_OK) == -1) {
552 				XI_message(("Creating new tabs directory\n"));
553 				gui_save_tabs(filename);
554 			}
555 			file = g_strdup_printf("%s%s", tabs_dir, filename);
556 			g_free(tabs_dir);
557 		}
558 
559 		/* we need this for first time non tabbed browsing */
560 		if (!settings.browsing && g_access(file, F_OK) == -1) {
561 			_save_off_tab(filename);
562 		}
563 		//xml_filename = (const xmlChar *) file;
564 		xml_doc = xmlParseFile(file);
565 		g_free(file);
566 		if (xml_doc == NULL) {
567 			gui_generic_warning_modal("Tabs document not parsed successfully.");
568 			error = TRUE;
569 		} else {
570 			tmp_node = xmlDocGetRootElement(xml_doc);
571 			if (tmp_node == NULL) {
572 				gui_generic_warning_modal("Tabs document is empty.");
573 				xmlFreeDoc(xml_doc);
574 				error = TRUE;
575 			} else if (xmlStrcmp(tmp_node->name,
576 					     (const xmlChar *)"Xiphos_Tabs")) {
577 				gui_generic_warning_modal("Tabs document has wrong type, root node != Xiphos_Tabs");
578 				xmlFreeDoc(xml_doc);
579 				error = TRUE;
580 			}
581 		}
582 
583 		if (error == FALSE) {
584 			for (childnode = tmp_node->children;
585 			     childnode != NULL;
586 			     childnode = childnode->next) {
587 				if (!xmlStrcmp(childnode->name,
588 					       (const xmlChar *)"tabs")) {
589 					tmp_node = childnode;
590 					for (tmp_node = tmp_node->children;
591 					     tmp_node != NULL;
592 					     tmp_node = tmp_node->next) {
593 						if (!xmlStrcmp(tmp_node->name,
594 							       (const xmlChar *)"tab")) {
595 							gchar *val;
596 
597 							pt = g_new0(PASSAGE_TAB_INFO,
598 								    1);
599 							if (pt_first ==
600 							    NULL)
601 								pt_first =
602 								    pt;
603 
604 							/* load per-tab module information. */
605 							val = (gchar *)
606 							    xmlGetProp(tmp_node,
607 								       (const xmlChar *)"text_mod");
608 							pt->text_mod =
609 							    g_strdup(val);
610 							xmlFree(val);
611 							val = (gchar *)
612 							    xmlGetProp(tmp_node,
613 								       (const xmlChar *)"commentary_mod");
614 							pt->commentary_mod =
615 							    g_strdup(val);
616 							xmlFree(val);
617 							val = (gchar *)
618 							    xmlGetProp(tmp_node,
619 								       (const xmlChar *)"dictlex_mod");
620 							pt->dictlex_mod =
621 							    g_strdup(val);
622 							xmlFree(val);
623 							val = (gchar *)
624 							    xmlGetProp(tmp_node,
625 								       (const xmlChar *)"book_mod");
626 							pt->book_mod =
627 							    g_strdup(val);
628 							xmlFree(val);
629 							val = (gchar *)
630 							    xmlGetProp(tmp_node,
631 								       (const xmlChar *)"text_commentary_key");
632 							pt->text_commentary_key = g_strdup(val);
633 							xmlFree(val);
634 							val = (gchar *)
635 							    xmlGetProp(tmp_node,
636 								       (const xmlChar *)"dictlex_key");
637 							pt->dictlex_key =
638 							    g_strdup(val);
639 							xmlFree(val);
640 							val = (gchar *)
641 							    xmlGetProp(tmp_node,
642 								       (const xmlChar *)"book_offset");
643 							pt->book_offset =
644 							    g_strdup(val);
645 							xmlFree(val);
646 							val = (gchar *)
647 							    xmlGetProp(tmp_node,
648 								       (const xmlChar *)"comm_showing");
649 							pt->comm_showing =
650 							    yes_no2true_false(val);
651 							xmlFree(val);
652 							val = (gchar *)
653 							    xmlGetProp(tmp_node,
654 								       (const xmlChar *)"showparallel");
655 							pt->showparallel =
656 							    yes_no2true_false(val);
657 							xmlFree(val);
658 							if (pt->showparallel) {
659 								settings.showparatab = TRUE;
660 								pt->paratab =
661 								    gui_create_parallel_tab();
662 								gtk_box_pack_start(GTK_BOX(widgets.page),
663 										   pt->paratab,
664 										   TRUE,
665 										   TRUE,
666 										   0);
667 								gtk_widget_hide(pt->paratab);
668 								gui_parallel_tab_sync((gchar *)
669 										      settings.currentverse);
670 								settings.showparatab = TRUE;
671 								sync_on =
672 								    TRUE;
673 							} else
674 								pt->paratab = NULL;
675 
676 							/*
677 							 * load per-tab "show" state.
678 							 * includes backward compatibility:
679 							 * if there is no per-tab state,
680 							 * take tab state from global state.
681 							 */
682 							if ((val =
683 								 (gchar *)
684 							     xmlGetProp(tmp_node,
685 									(const xmlChar *)"showtexts"))) {
686 								pt->showtexts = yes_no2true_false(val);
687 								xmlFree(val);
688 								val =
689 								    (gchar *)
690 								    xmlGetProp(tmp_node,
691 									       (const xmlChar *)"showpreview");
692 								pt->showpreview = yes_no2true_false(val);
693 								xmlFree(val);
694 								val =
695 								    (gchar *)
696 								    xmlGetProp(tmp_node,
697 									       (const xmlChar *)"showcomms");
698 								pt->showcomms = yes_no2true_false(val);
699 								xmlFree(val);
700 								val =
701 								    (gchar *)
702 								    xmlGetProp(tmp_node,
703 									       (const xmlChar *)"showdicts");
704 								pt->showdicts = yes_no2true_false(val);
705 								xmlFree(val);
706 
707 							} else {
708 								pt->showtexts = settings.showtexts;
709 								pt->showpreview = settings.showpreview;
710 								pt->showcomms = settings.showcomms;
711 								pt->showdicts = settings.showdicts;
712 								back_compat_need_save = TRUE;
713 							}
714 
715 							pt->history_items =
716 							    0;
717 							pt->current_history_item = 0;
718 							pt->first_back_click = TRUE;
719 							main_add_tab_history_item((PASSAGE_TAB_INFO *)pt);
720 
721 							gui_reassign_strdup(&settings.currentverse,
722 									    pt->text_commentary_key);
723 
724 							passage_list =
725 							    g_list_append(passage_list,
726 									  (PASSAGE_TAB_INFO *)pt);
727 							notebook_main_add_page(pt);
728 						}
729 					}
730 				}
731 			}
732 		}
733 		xmlFreeDoc(xml_doc);
734 
735 		/* backward compatibility completion. */
736 		if (back_compat_need_save)
737 			gui_save_tabs(filename);
738 
739 		if (error == TRUE || pt == NULL) {
740 			pt = g_new0(PASSAGE_TAB_INFO, 1);
741 			pt->text_mod = g_strdup(settings.MainWindowModule);
742 			pt->commentary_mod =
743 			    g_strdup(settings.CommWindowModule);
744 			pt->dictlex_mod =
745 			    g_strdup(settings.DictWindowModule);
746 			pt->book_mod = g_strdup(settings.book_mod); //NULL;
747 			pt->text_commentary_key =
748 			    g_strdup(settings.currentverse);
749 			pt->dictlex_key = g_strdup(settings.dictkey);
750 			pt->book_offset = NULL; //settings.book_offset = atol(xml_get_value( "keys", "offset"));
751 
752 			pt->paratab = NULL;
753 
754 			pt->showtexts = settings.showtexts;
755 			pt->showpreview = settings.showpreview;
756 			pt->showcomms = settings.showcomms;
757 			pt->showdicts = settings.showdicts;
758 
759 			pt->history_items = 0;
760 			pt->current_history_item = 0;
761 			pt->first_back_click = TRUE;
762 			//                      main_add_tab_history_item((PASSAGE_TAB_INFO*)pt);
763 			passage_list =
764 			    g_list_append(passage_list,
765 					  (PASSAGE_TAB_INFO *)pt);
766 			notebook_main_add_page(pt);
767 		} else {
768 			// first passage is current/displayed.
769 			pt = pt_first;
770 
771 			pt->paratab = NULL;
772 			// This is a hack to keep gs from loading the settings
773 			// from the last session into the last tab loaded here.
774 			gui_reassign_strdup(&settings.MainWindowModule,
775 					    pt->text_mod);
776 			gui_reassign_strdup(&settings.CommWindowModule,
777 					    pt->commentary_mod);
778 			gui_reassign_strdup(&settings.DictWindowModule,
779 					    pt->dictlex_mod);
780 			gui_reassign_strdup(&settings.book_mod,
781 					    pt->book_mod);
782 			gui_reassign_strdup(&settings.currentverse,
783 					    pt->text_commentary_key);
784 			gui_reassign_strdup(&settings.dictkey,
785 					    pt->dictlex_key);
786 			settings.book_offset = atol(pt->book_offset);
787 		}
788 	}
789 
790 	stop_refresh = FALSE;
791 	set_current_tab(pt);
792 	gui_recompute_view_menu_choices();
793 }
794 
795 /******************************************************************************
796  * Name
797  *  on_notebook_main_close_page
798  *
799  * Synopsis
800  *   #include "tabbed_browser.h"
801  *
802  *   void on_notebook_main_close_page(GtkButton * button, gpointer user_data)
803  *
804  * Description
805  *
806  *
807  * Return value
808  *   void
809  */
810 
on_notebook_main_close_page(GtkButton * button,gpointer user_data)811 static void on_notebook_main_close_page(GtkButton *button,
812 					gpointer user_data)
813 {
814 	PASSAGE_TAB_INFO *pt = (PASSAGE_TAB_INFO *)user_data;
815 	closing_tab = TRUE;
816 	gui_close_passage_tab(gtk_notebook_page_num(GTK_NOTEBOOK(widgets.notebook_main),
817 						    pt->page_widget));
818 	closing_tab = FALSE;
819 }
820 
821 /******************************************************************************
822  * Name
823  *  tab_widget_new
824  *
825  * Synopsis
826  *   #include "tabbed_browser.h"
827  *
828  *   GtkWidget* tab_widget_new(PASSAGE_TAB_INFO *tbinf,const gchar *label_text)
829  *
830  * Description
831  *   creates a tab widget that contains a label and a close button
832  *
833  * Return value
834  *   GtkWidget*
835  */
836 
tab_widget_new(PASSAGE_TAB_INFO * tbinf,const gchar * label_text)837 static GtkWidget *tab_widget_new(PASSAGE_TAB_INFO *tbinf,
838 				 const gchar *label_text)
839 {
840 	GtkWidget *box;
841 #ifdef USE_GTK_3
842 //	GdkRGBA color;
843 #else
844 	GdkColor color;
845 #endif
846 
847 	g_return_val_if_fail(label_text != NULL, NULL);
848 #if GTK_CHECK_VERSION(3, 10, 0)
849 	tbinf->button_close = gtk_button_new_from_icon_name("window-close-symbolic", GTK_ICON_SIZE_MENU);
850 #if GTK_CHECK_VERSION(3, 20, 0)
851 	gtk_button_set_relief(GTK_BUTTON(tbinf->button_close), GTK_RELIEF_NONE);
852 #else
853 #endif
854 #else
855 	GtkWidget *tmp_toolbar_icon = gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
856 	tbinf->button_close = gtk_button_new();
857 	gtk_button_set_image(GTK_BUTTON(tbinf->button_close), tmp_toolbar_icon);
858 	gtk_button_set_relief(GTK_BUTTON(tbinf->button_close), GTK_RELIEF_NONE);
859 #endif
860 
861 #ifndef USE_GTK_3
862 	gtk_rc_parse_string("style \"tab-button-style\"\n"
863 			    "{\n"
864 			    "    GtkWidget::focus-padding = 0\n"
865 			    "    GtkWidget::focus-line-width = 0\n"
866 			    "    xthickness = 0\n"
867 			    "    ythickness = 0\n"
868 			    "    GtkButton::internal-border = {0, 0, 0, 0}\n"
869 			    "    GtkButton::default-border = {0, 0, 0, 0}\n"
870 			    "    GtkButton::default-outside-border = {0, 0, 0, 0}\n"
871 			    "}\n"
872 			    "widget \"*.button-close\" style \"tab-button-style\"");
873 	gtk_widget_set_name(GTK_WIDGET(tbinf->button_close),
874 			    "button-close");
875 #else
876 	gtk_widget_set_size_request(tbinf->button_close, 18, 16);
877 #endif
878 
879 #ifndef USE_GTK_3
880 	GtkRequisition r;
881 	gtk_widget_size_request(tbinf->button_close, &r);
882 #endif
883 
884 	gtk_widget_set_sensitive(tbinf->button_close, FALSE);
885 	gtk_widget_show(tbinf->button_close);
886 	tbinf->tab_label = GTK_LABEL(gtk_label_new(label_text));
887 	gtk_widget_show(GTK_WIDGET(tbinf->tab_label));
888 
889 #ifdef USE_GTK_3
890 #else
891 	color.red = 0;
892 	color.green = 0;
893 	color.blue = 0;
894 
895 	gtk_widget_modify_fg(tbinf->button_close, GTK_STATE_NORMAL,
896 			     &color);
897 	gtk_widget_modify_fg(tbinf->button_close, GTK_STATE_INSENSITIVE,
898 			     &color);
899 	gtk_widget_modify_fg(tbinf->button_close, GTK_STATE_ACTIVE,
900 			     &color);
901 	gtk_widget_modify_fg(tbinf->button_close, GTK_STATE_PRELIGHT,
902 			     &color);
903 	gtk_widget_modify_fg(tbinf->button_close, GTK_STATE_SELECTED,
904 			     &color);
905 #endif
906 
907 	UI_HBOX(box, FALSE, 0);
908 	gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(tbinf->tab_label),
909 			   TRUE, TRUE, 0);
910 	gtk_box_pack_start(GTK_BOX(box), tbinf->button_close, FALSE, FALSE,
911 			   0);
912 
913 	gtk_widget_show(box);
914 
915 	g_signal_connect(G_OBJECT(tbinf->button_close), "clicked",
916 			 G_CALLBACK(on_notebook_main_close_page), tbinf);
917 
918 	return box;
919 }
920 
921 /******************************************************************************
922  * Name
923  *  gui_notebook_main_switch_page
924  *
925  * Synopsis
926  *   #include "tabbed_browser.h"
927  *
928  *   void gui_notebook_main_switch_page(GtkNotebook * notebook,
929  *				  GtkNotebookPage * page,
930  *				  gint page_num, GList * tl)
931  *
932  * Description
933  *   sets gui to new passage
934  *
935  * Return value
936  *   void
937  */
938 #ifdef USE_GTK_3
gui_notebook_main_switch_page(GtkNotebook * notebook,gpointer arg,gint page_num,GList ** tl)939 void gui_notebook_main_switch_page(GtkNotebook *notebook,
940 				   gpointer arg,
941 				   gint page_num, GList **tl)
942 #else
943 void gui_notebook_main_switch_page(GtkNotebook *notebook,
944 				   GtkNotebookPage *page,
945 				   gint page_num, GList **tl)
946 #endif
947 {
948 	gboolean comm_showing;
949 	gint number_of_pages = gtk_notebook_get_n_pages(notebook);
950 	PASSAGE_TAB_INFO *pt;
951 
952 	if (stop_refresh)
953 		return;
954 
955 	XI_message(("on_notebook_main_switch_page"));
956 	page_change = TRUE;
957 	/* get data structure for new passage */
958 	/*
959 	 * this is needed to stop seg fault if the left tab is closed when
960 	 * there are only two tabs - because number_of_pages equals 2 even
961 	 * thought there is only 1.
962 	 */
963 	if (number_of_pages == 2 && removed_page == 0)
964 		pt = (PASSAGE_TAB_INFO *)g_list_nth_data(*tl, 0);
965 	else
966 		pt = (PASSAGE_TAB_INFO *)g_list_nth_data(*tl, page_num);
967 	removed_page = 1;
968 //cur_passage_tab = pt;
969 
970 #ifdef USE_TREEVIEW_PATH
971 	if (cur_passage_tab && cur_passage_tab->book_mod)
972 		gui_collapse_treeview_to_book(GTK_TREE_VIEW(sidebar.module_list),
973 					      cur_passage_tab->book_mod);
974 #endif /* USE_TREEVIEW_PATH */
975 
976 	if (!pt->showparallel) {
977 		if (cur_passage_tab && cur_passage_tab->paratab)
978 			gtk_widget_hide(cur_passage_tab->paratab);
979 		gtk_widget_show(widgets.hpaned);
980 	}
981 
982 	set_current_tab(pt);
983 
984 	companion_activity = TRUE;
985 	if (pt->showparallel) {
986 		gtk_widget_hide(widgets.hpaned);
987 		if (pt->paratab)
988 			gtk_widget_show(pt->paratab);
989 		companion_activity = FALSE;
990 		page_change = FALSE;
991 		settings.paratab_showing = TRUE;
992 		return;
993 	} else
994 		settings.paratab_showing = FALSE;
995 
996 	//sets the book mod and key
997 	main_display_book(pt->book_mod, pt->book_offset);
998 
999 #ifdef USE_TREEVIEW_PATH
1000 	if (pt->showcomms && pt->book_mod)
1001 		gui_expand_treeview_to_path(GTK_TREE_VIEW(sidebar.module_list),
1002 					    pt->book_mod);
1003 #endif /* USE_TREEVIEW_PATH */
1004 
1005 	comm_showing = settings.comm_showing;
1006 	settings.comm_showing = 1;
1007 	//sets the commentary mod and key
1008 	main_display_commentary(pt->commentary_mod,
1009 				pt->text_commentary_key);
1010 	settings.comm_showing = comm_showing;
1011 	//sets the text mod and key
1012 	main_display_bible(pt->text_mod, pt->text_commentary_key);
1013 
1014 	navbar_versekey.module_name =
1015 	    g_string_assign(navbar_versekey.module_name, pt->text_mod);
1016 	navbar_versekey.key =
1017 	    g_string_assign(navbar_versekey.key, pt->text_commentary_key);
1018 	main_update_nav_controls(navbar_versekey.module_name->str,
1019 				 pt->text_commentary_key);
1020 
1021 	//sets the dictionary mod and key
1022 	main_display_dictionary(pt->dictlex_mod, pt->dictlex_key);
1023 
1024 	gtk_notebook_set_current_page(GTK_NOTEBOOK(widgets.notebook_comm_book),
1025 				      (pt->comm_showing ? 0 : 1));
1026 
1027 	gui_recompute_view_menu_choices();
1028 
1029 	companion_activity = FALSE;
1030 
1031 	page_change = FALSE;
1032 }
1033 
1034 /******************************************************************************
1035  * Name
1036  *  gui_select_nth_tab
1037  *
1038  * Synopsis
1039  *   #include "tabbed_browser.h"
1040  *
1041  *   void gui_select_nth_tab(gint page_num)
1042  *
1043  * Description
1044  *   from ctrl-DIGIT in main_window.c, select a tab.
1045  *   the tab list is 0-based: page_num must already be 0-normalized.
1046  *
1047  * Return value
1048  *   void
1049  */
1050 
gui_select_nth_tab(gint page_num)1051 void gui_select_nth_tab(gint page_num)
1052 {
1053 	gint number_of_pages =
1054 	    gtk_notebook_get_n_pages(GTK_NOTEBOOK(widgets.notebook_main));
1055 
1056 	/* within bounds of available tabs? */
1057 	if (page_num >= number_of_pages)
1058 		return;
1059 
1060 	settings.tab_page = page_num;
1061 	gtk_notebook_set_current_page(GTK_NOTEBOOK(widgets.notebook_main),
1062 				      page_num);
1063 	gui_notebook_main_switch_page(GTK_NOTEBOOK(widgets.notebook_main),
1064 				      NULL, page_num, &passage_list);
1065 }
1066 
1067 /******************************************************************************
1068  * Name
1069  *  gui_set_tab_label
1070  *
1071  * Synopsis
1072  *   #include "tabbed_browser.h"
1073 if *
1074  *   void gui_set_tab_label(const char *key, gboolean one_tab)
1075  *
1076  * Description
1077  *   sets tab label(s) to current verse.
1078  *   dependent on linkedtabs setting, either just cur or all.
1079  *   one_tab means don't loop the set, just set current.
1080  *
1081  * Return value
1082  *   void
1083  */
1084 
gui_set_tab_label(const gchar * key,gboolean one_tab)1085 void gui_set_tab_label(const gchar *key, gboolean one_tab)
1086 {
1087 	if (stop_refresh)
1088 		return;
1089 
1090 	if ((settings.linkedtabs && !one_tab) || (cur_passage_tab == NULL)) {
1091 		GList *tmp = NULL;
1092 		for (tmp = g_list_first(passage_list); tmp != NULL;
1093 		     tmp = g_list_next(tmp))
1094 			gui_set_named_tab_label(key, (PASSAGE_TAB_INFO *)
1095 						     tmp->data,
1096 						((PASSAGE_TAB_INFO *)
1097 						 tmp->data ==
1098 						 cur_passage_tab));
1099 	} else {
1100 		gui_set_named_tab_label(key, cur_passage_tab, TRUE);
1101 	}
1102 }
1103 
1104 /******************************************************************************
1105  * Name
1106  *  gui_set_named_tab_label
1107  *
1108  * Synopsis
1109  *   #include "tabbed_browser.h"
1110  *
1111  *   void gui_set_named_tab_label(const char *key, PASSAGE_TAB_INFO *pt)
1112  *
1113  * Description
1114  *   sets specified tab label to current verse
1115  *
1116  * Return value
1117  *   void
1118  */
1119 
gui_set_named_tab_label(const gchar * key,PASSAGE_TAB_INFO * pt,gboolean update)1120 void gui_set_named_tab_label(const gchar *key, PASSAGE_TAB_INFO *pt,
1121 			     gboolean update)
1122 {
1123 	GString *str;
1124 
1125 	if (stop_refresh)
1126 		return;
1127 
1128 	gui_reassign_strdup(&pt->text_commentary_key, (char *)key);
1129 	str = pick_tab_label(pt);
1130 
1131 	gtk_label_set_text(pt->tab_label, str->str);
1132 	gtk_notebook_set_menu_label_text(GTK_NOTEBOOK(widgets.notebook_main),
1133 					 pt->page_widget, str->str);
1134 	if (update)
1135 		main_add_tab_history_item((PASSAGE_TAB_INFO *)pt);
1136 	g_string_free(str, TRUE);
1137 }
1138 
1139 /******************************************************************************
1140  * Name
1141  *
1142  *
1143  * Synopsis
1144  *   #include "tabbed_browser.h"
1145  *
1146  *
1147  *
1148  * Description
1149  *
1150  *
1151  * Return value
1152  *   void
1153  */
1154 
gui_update_tab_struct(const gchar * text_mod,const gchar * commentary_mod,const gchar * dictlex_mod,const gchar * book_mod,const gchar * dictlex_key,const gchar * book_offset,gboolean comm_showing,gboolean showtexts,gboolean showpreview,gboolean showcomms,gboolean showdicts)1155 void gui_update_tab_struct(const gchar *text_mod,
1156 			   const gchar *commentary_mod,
1157 			   const gchar *dictlex_mod,
1158 			   const gchar *book_mod,
1159 			   const gchar *dictlex_key,
1160 			   const gchar *book_offset,
1161 			   gboolean comm_showing,
1162 			   gboolean showtexts,
1163 			   gboolean showpreview,
1164 			   gboolean showcomms, gboolean showdicts)
1165 {
1166 	if (stop_refresh)
1167 		return;
1168 
1169 	/*	if (!settings.browsing)
1170 	        return;
1171 */
1172 
1173 	if (page_change)
1174 		return;
1175 	if (!cur_passage_tab)
1176 		return;
1177 	cur_passage_tab->showtexts = showtexts;
1178 	cur_passage_tab->showpreview = showpreview;
1179 	cur_passage_tab->showcomms = showcomms;
1180 	cur_passage_tab->showdicts = showdicts;
1181 
1182 	if (text_mod) {
1183 		gui_reassign_strdup(&cur_passage_tab->text_mod,
1184 				    (char *)text_mod);
1185 	}
1186 	if (commentary_mod) {
1187 		cur_passage_tab->comm_showing = comm_showing;
1188 		gui_reassign_strdup(&cur_passage_tab->commentary_mod,
1189 				    (char *)commentary_mod);
1190 	}
1191 	if (dictlex_mod) {
1192 		gui_reassign_strdup(&cur_passage_tab->dictlex_mod,
1193 				    (char *)dictlex_mod);
1194 	}
1195 	if (book_mod) {
1196 		cur_passage_tab->comm_showing = comm_showing;
1197 		gui_reassign_strdup(&cur_passage_tab->book_mod,
1198 				    (char *)book_mod);
1199 	}
1200 	if (book_offset) {
1201 		gui_reassign_strdup(&cur_passage_tab->book_offset,
1202 				    (char *)book_offset);
1203 	}
1204 	if (dictlex_key) {
1205 		gui_reassign_strdup(&cur_passage_tab->dictlex_key,
1206 				    (char *)dictlex_key);
1207 	}
1208 }
1209 
1210 /******************************************************************************
1211  * Name
1212  *  gui_open_passage_in_new_tab
1213  *
1214  * Synopsis
1215  *   #include "tabbed_browser.h"
1216  *
1217  *   void gui_open_passage_in_new_tab(gchar *verse_key)
1218  *
1219  * Description
1220  *   opens the given verse in a new passage tab
1221  *
1222  * Return value
1223  *   void
1224  */
gui_open_passage_in_new_tab(gchar * verse_key)1225 void gui_open_passage_in_new_tab(gchar *verse_key)
1226 {
1227 	PASSAGE_TAB_INFO *pt;
1228 
1229 	if (stop_refresh)
1230 		return;
1231 
1232 	if (!settings.browsing)
1233 		return;
1234 
1235 	if ((pt = g_new0(PASSAGE_TAB_INFO, 1)) == NULL) {
1236 		gui_generic_warning("Could not allocate a new tab");
1237 		return;
1238 	}
1239 	pt->text_mod = g_strdup(settings.MainWindowModule);
1240 	pt->commentary_mod = g_strdup(settings.CommWindowModule);
1241 	pt->dictlex_mod = g_strdup(settings.DictWindowModule);
1242 	pt->book_mod = g_strdup(settings.book_mod);
1243 	pt->paratab = NULL;
1244 
1245 	pt->text_commentary_key = g_strdup(verse_key);
1246 	pt->dictlex_key = g_strdup(settings.dictkey);
1247 	pt->book_offset = g_strdup_printf("%ld", settings.book_offset);
1248 	pt->comm_showing = settings.comm_showing;
1249 
1250 	if (cur_passage_tab && cur_passage_tab->showparallel) {
1251 		pt->showtexts = 1;
1252 		pt->showcomms = 1;
1253 		pt->showdicts = 1;
1254 	} else {
1255 		pt->showtexts = settings.showtexts;
1256 		pt->showcomms = settings.showcomms;
1257 		pt->showdicts = settings.showdicts;
1258 	}
1259 
1260 	pt->showpreview = settings.showpreview;
1261 	pt->showparallel = FALSE;
1262 
1263 	pt->history_items = 0;
1264 	pt->current_history_item = 0;
1265 	pt->first_back_click = TRUE;
1266 	main_add_tab_history_item((PASSAGE_TAB_INFO *)pt);
1267 
1268 	passage_list =
1269 	    g_list_append(passage_list, (PASSAGE_TAB_INFO *)pt);
1270 	//set_current_tab(pt);
1271 	notebook_main_add_page(pt);
1272 
1273 	gtk_notebook_set_current_page(GTK_NOTEBOOK(widgets.notebook_main),
1274 				      gtk_notebook_page_num(GTK_NOTEBOOK(widgets.notebook_main),
1275 							    pt->page_widget));
1276 }
1277 
1278 /******************************************************************************
1279  * Name
1280  *  gui_open_parallel_view_in_new_tab
1281  *
1282  * Synopsis
1283  *   #include "tabbed_browser.h"
1284  *
1285  *   void gui_open_parallel_view_in_new_tab(void)
1286  *
1287  * Description
1288  *   opens the parallel view in a new tab
1289  *
1290  * Return value
1291  *   void
1292  */
1293 
gui_open_parallel_view_in_new_tab(void)1294 void gui_open_parallel_view_in_new_tab(void)
1295 {
1296 	PASSAGE_TAB_INFO *pt;
1297 
1298 	if (stop_refresh)
1299 		return;
1300 
1301 	if (!settings.browsing)
1302 		return;
1303 
1304 	if ((pt = g_new0(PASSAGE_TAB_INFO, 1)) == NULL) {
1305 		gui_generic_warning("Could not allocate a new tab");
1306 		return;
1307 	}
1308 
1309 	pt->showtexts = FALSE;
1310 	pt->showpreview = TRUE;
1311 	pt->showcomms = FALSE;
1312 	pt->showdicts = FALSE;
1313 	pt->showparallel = TRUE;
1314 	pt->text_mod = g_strdup(settings.MainWindowModule);
1315 	pt->commentary_mod = g_strdup(settings.CommWindowModule);
1316 	pt->dictlex_mod = g_strdup(settings.DictWindowModule);
1317 	pt->book_mod = g_strdup(settings.book_mod);
1318 	pt->showbookeditor = FALSE;
1319 	pt->comm_showing = FALSE;
1320 
1321 	pt->text_commentary_key = g_strdup(settings.currentverse);
1322 	pt->dictlex_key = g_strdup(settings.dictkey);
1323 	pt->book_offset = g_strdup_printf("%ld", settings.book_offset);
1324 
1325 	passage_list =
1326 	    g_list_append(passage_list, (PASSAGE_TAB_INFO *)pt);
1327 	set_current_tab(pt);
1328 	gui_recompute_view_menu_choices();
1329 	notebook_main_add_page(pt);
1330 	pt->paratab = gui_create_parallel_tab();
1331 	gui_parallel_tab_sync((gchar *)settings.currentverse);
1332 	/*gtk_box_pack_start(GTK_BOX(widgets.page), pt->paratab, TRUE, TRUE,
1333 	   0); */
1334 	gtk_notebook_set_current_page(GTK_NOTEBOOK(widgets.notebook_main),
1335 				      gtk_notebook_page_num(GTK_NOTEBOOK(widgets.notebook_main),
1336 							    pt->page_widget));
1337 }
1338 
1339 /******************************************************************************
1340  * Name
1341  *  gui_open_module_in_new_tab
1342  *
1343  * Synopsis
1344  *   #include "tabbed_browser.h"
1345  *
1346  *   void gui_open_module_in_new_tab(gchar *verse_key)
1347  *
1348  * Description
1349  *   opens the given module in a new passage tab
1350  *
1351  * Return value
1352  *   void
1353  */
1354 
gui_open_module_in_new_tab(gchar * module)1355 void gui_open_module_in_new_tab(gchar *module)
1356 {
1357 	PASSAGE_TAB_INFO *pt;
1358 	gint module_type;
1359 
1360 	if (stop_refresh)
1361 		return;
1362 
1363 	if (!settings.browsing)
1364 		return;
1365 
1366 	if ((pt = g_new0(PASSAGE_TAB_INFO, 1)) == NULL) {
1367 		gui_generic_warning("Could not allocate a new tab");
1368 		return;
1369 	}
1370 	module_type = main_get_mod_type(module);
1371 
1372 	pt->showtexts = FALSE;
1373 	pt->showpreview = settings.showpreview;
1374 	pt->showcomms = FALSE;
1375 	pt->showdicts = FALSE;
1376 	pt->showparallel = FALSE;
1377 	pt->paratab = NULL;
1378 
1379 	switch (module_type) {
1380 	case -1:
1381 		return;
1382 		break;
1383 	case TEXT_TYPE:
1384 		pt->text_mod = g_strdup(module);
1385 		pt->commentary_mod = g_strdup(settings.CommWindowModule);
1386 		pt->dictlex_mod = g_strdup(settings.DictWindowModule);
1387 		pt->book_mod = g_strdup(settings.book_mod);
1388 		pt->showtexts = TRUE;
1389 		break;
1390 	case COMMENTARY_TYPE:
1391 		pt->text_mod = g_strdup(settings.MainWindowModule);
1392 		pt->commentary_mod = g_strdup(module);
1393 		pt->dictlex_mod = g_strdup(settings.DictWindowModule);
1394 		pt->book_mod = g_strdup(settings.book_mod);
1395 		pt->showcomms = TRUE;
1396 		pt->comm_showing = 1;
1397 		break;
1398 	case DICTIONARY_TYPE:
1399 		pt->text_mod = g_strdup(settings.MainWindowModule);
1400 		pt->commentary_mod = g_strdup(settings.CommWindowModule);
1401 		pt->dictlex_mod = g_strdup(module);
1402 		pt->book_mod = g_strdup(settings.book_mod);
1403 		pt->showdicts = TRUE;
1404 		break;
1405 	case BOOK_TYPE:
1406 		pt->text_mod = g_strdup(settings.MainWindowModule);
1407 		pt->commentary_mod = g_strdup(settings.CommWindowModule);
1408 		pt->dictlex_mod = g_strdup(settings.DictWindowModule);
1409 		pt->book_mod = g_strdup(module);
1410 		pt->showcomms = TRUE;
1411 		pt->comm_showing = 0;
1412 		break;
1413 	case PRAYERLIST_TYPE:
1414 		pt->text_mod = g_strdup(settings.MainWindowModule);
1415 		pt->commentary_mod = g_strdup(settings.CommWindowModule);
1416 		pt->dictlex_mod = g_strdup(settings.DictWindowModule);
1417 		pt->book_mod = g_strdup(module);
1418 		pt->showcomms = TRUE;
1419 		pt->comm_showing = 0;
1420 		break;
1421 	}
1422 
1423 	pt->text_commentary_key = g_strdup(settings.currentverse);
1424 	pt->dictlex_key = g_strdup(settings.dictkey);
1425 	pt->book_offset = g_strdup_printf("%ld", settings.book_offset);
1426 
1427 	passage_list =
1428 	    g_list_append(passage_list, (PASSAGE_TAB_INFO *)pt);
1429 	//set_current_tab(pt);
1430 	notebook_main_add_page(pt);
1431 
1432 	gtk_notebook_set_current_page(GTK_NOTEBOOK(widgets.notebook_main),
1433 				      gtk_notebook_page_num(GTK_NOTEBOOK(widgets.notebook_main),
1434 							    pt->page_widget));
1435 }
1436 
1437 /******************************************************************************
1438  * Name
1439  *  gui_close_all_tabs
1440  *
1441  * Synopsis
1442  *   #include "tabbed_browser.h"
1443  *
1444  *   void gui_close_all_tabs(void)
1445  *
1446  * Description
1447  *   called from preferences dialog when disable browsing is chosen
1448  *
1449  * Return value
1450  *   void
1451  */
1452 
gui_close_all_tabs(void)1453 void gui_close_all_tabs(void)
1454 {
1455 	gint i;
1456 	gint number_of_pages =
1457 	    gtk_notebook_get_n_pages(GTK_NOTEBOOK(widgets.notebook_main));
1458 
1459 	if (stop_refresh)
1460 		return;
1461 
1462 	for (i = number_of_pages - 1; i > -1; i--) {
1463 		PASSAGE_TAB_INFO *pt =
1464 		    (PASSAGE_TAB_INFO *)g_list_nth_data(passage_list,
1465 							(guint)i);
1466 		passage_list = g_list_remove(passage_list, pt);
1467 		g_free(pt->text_mod);
1468 		g_free(pt->commentary_mod);
1469 		g_free(pt->dictlex_mod);
1470 		g_free(pt->book_mod);
1471 		g_free(pt->text_commentary_key);
1472 		g_free(pt->dictlex_key);
1473 		g_free(pt->book_offset);
1474 		g_free(pt);
1475 		gtk_notebook_remove_page(GTK_NOTEBOOK(widgets.notebook_main), i);
1476 	}
1477 
1478 	g_list_free(passage_list);
1479 	passage_list = NULL;
1480 	cur_passage_tab = NULL;
1481 	//      gui_set_text_frame_label(cur_t);
1482 }
1483 
1484 /******************************************************************************
1485  * Name
1486  *  gui_close_passage_tab
1487  *
1488  * Synopsis
1489  *   #include "tabbed_browser.h"
1490  *
1491  *   void gui_close_passage_tab(gint pagenum)
1492  *
1493  * Description
1494  *   closes the given passage tab or the current one if pagenum = -1
1495  *
1496  * Return value
1497  *   void
1498  */
gui_close_passage_tab(gint pagenum)1499 void gui_close_passage_tab(gint pagenum)
1500 {
1501 	if (stop_refresh)
1502 		return;
1503 
1504 	if (-1 == pagenum)
1505 		pagenum =
1506 		    gtk_notebook_get_current_page(GTK_NOTEBOOK(widgets.notebook_main));
1507 	if (1 ==
1508 	    gtk_notebook_get_n_pages(GTK_NOTEBOOK(widgets.notebook_main)))
1509 		return;
1510 	PASSAGE_TAB_INFO *pt =
1511 	    (PASSAGE_TAB_INFO *)g_list_nth_data(passage_list,
1512 						(guint)pagenum);
1513 	if (pt->showparallel || (2 <=
1514 				 gtk_notebook_get_n_pages(GTK_NOTEBOOK(widgets.notebook_main)))) {
1515 		// (surely this is always true!?)
1516 
1517 		if (pagenum > 0) {
1518 			gtk_notebook_set_current_page(GTK_NOTEBOOK(widgets.notebook_main), 0);
1519 			cur_passage_tab = (PASSAGE_TAB_INFO *)
1520 			    g_list_nth_data(passage_list, (guint)0);
1521 		}
1522 	}
1523 
1524 	stop_refresh = TRUE;
1525 	sync_windows();
1526 	stop_refresh = FALSE;
1527 
1528 	passage_list = g_list_remove(passage_list, pt);
1529 	if (pt->text_mod)
1530 		g_free(pt->text_mod);
1531 	if (pt->commentary_mod)
1532 		g_free(pt->commentary_mod);
1533 	if (pt->dictlex_mod)
1534 		g_free(pt->dictlex_mod);
1535 	if (pt->book_mod)
1536 		g_free(pt->book_mod);
1537 	if (pt->text_commentary_key)
1538 		g_free(pt->text_commentary_key);
1539 	if (pt->dictlex_key)
1540 		g_free(pt->dictlex_key);
1541 	if (pt->book_offset)
1542 		g_free(pt->book_offset);
1543 	if (pt->showparallel) {
1544 		gtk_widget_hide(pt->paratab);
1545 		gui_destroy_parallel_tab();
1546 		settings.showparatab = FALSE;
1547 		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widgets.parallel_tab_item),
1548 					       settings.showparatab);
1549 	}
1550 	g_free(pt);
1551 	//cur_passage_tab = NULL;
1552 	removed_page = pagenum;
1553 	gtk_notebook_remove_page(GTK_NOTEBOOK(widgets.notebook_main),
1554 				 pagenum);
1555 }
1556 
on_notebook_main_new_tab_clicked(GtkButton * button,gpointer user_data)1557 void on_notebook_main_new_tab_clicked(GtkButton *button,
1558 				      gpointer user_data)
1559 {
1560 	gui_open_passage_in_new_tab(settings.currentverse);
1561 }
1562 
1563 /******************************************************************************
1564  * Name
1565  *  gui_notebook_main_setup
1566  *
1567  * Synopsis
1568  *   #include "tabbed_browser.h"
1569  *
1570  *   void gui_notebook_main_setup(int tabs)
1571  *
1572  * Description
1573  *   set up notebook for browsing multiple passages
1574  *
1575  * Return value
1576  *   void
1577  */
gui_notebook_main_setup(int tabs,const char * tabsfile)1578 void gui_notebook_main_setup(int tabs, const char *tabsfile)
1579 {
1580 	if (stop_refresh)
1581 		return;
1582 
1583 	removed_page = 1;
1584 	cur_passage_tab = NULL;
1585 	passage_list = NULL;
1586 
1587 	gui_load_tabs(tabsfile ? tabsfile
1588 			       : (tabs ? default_tab_filename : no_tab_filename));
1589 
1590 	g_signal_connect(G_OBJECT(widgets.notebook_main),
1591 			 "switch-page",
1592 			 G_CALLBACK(gui_notebook_main_switch_page),
1593 			 &passage_list);
1594 
1595 	g_signal_connect(G_OBJECT(widgets.button_new_tab), "clicked",
1596 			 G_CALLBACK(on_notebook_main_new_tab_clicked),
1597 			 NULL);
1598 
1599 	//show the new tab button here instead of in main_window.c so it
1600 	//doesn't get shown if !settings.browsing
1601 	gtk_widget_show(widgets.button_new_tab);
1602 	gui_notebook_main_switch_page(GTK_NOTEBOOK(widgets.notebook_main),
1603 				      NULL,
1604 				      settings.tab_page, &passage_list);
1605 }
1606 
1607 /******************************************************************************
1608  * Name
1609  *  gui_notebook_main_shutdown
1610  *
1611  * Synopsis
1612  *   #include "tabbed_browser.h"
1613  *
1614  *  void gui_notebook_main_shutdown(int tabs)
1615  *
1616  * Description
1617  *   shut down main notebook and clean mem
1618  *
1619  * Return value
1620  *   void
1621  */
gui_notebook_main_shutdown(int tabs)1622 void gui_notebook_main_shutdown(int tabs)
1623 {
1624 	if (stop_refresh)
1625 		return;
1626 
1627 	gui_save_tabs(tabs ? default_tab_filename : no_tab_filename);
1628 	passage_list = g_list_first(passage_list);
1629 	while (passage_list != NULL) {
1630 		PASSAGE_TAB_INFO *pt =
1631 		    (PASSAGE_TAB_INFO *)passage_list->data;
1632 		g_free(pt->text_mod);
1633 		g_free(pt->commentary_mod);
1634 		g_free(pt->dictlex_mod);
1635 		g_free(pt->book_mod);
1636 		g_free(pt->text_commentary_key);
1637 		g_free(pt->dictlex_key);
1638 		g_free(pt->book_offset);
1639 		g_free((PASSAGE_TAB_INFO *)passage_list->data);
1640 		passage_list = g_list_next(passage_list);
1641 	}
1642 	g_list_free(passage_list);
1643 	cur_passage_tab = NULL;
1644 }
1645 
gui_tab_set_showtexts(int show)1646 void gui_tab_set_showtexts(int show)
1647 {
1648 	if (cur_passage_tab)
1649 		cur_passage_tab->showtexts = show;
1650 }
1651 
gui_tab_set_showpreview(int show)1652 void gui_tab_set_showpreview(int show)
1653 {
1654 	if (cur_passage_tab)
1655 		cur_passage_tab->showpreview = show;
1656 }
1657 
gui_tab_set_showcomms(int show)1658 void gui_tab_set_showcomms(int show)
1659 {
1660 	if (cur_passage_tab)
1661 		cur_passage_tab->showcomms = show;
1662 }
1663 
gui_tab_set_showdicts(int show)1664 void gui_tab_set_showdicts(int show)
1665 {
1666 	if (cur_passage_tab)
1667 		cur_passage_tab->showdicts = show;
1668 }
1669 
_is_paratab_showing(void)1670 static int _is_paratab_showing(void)
1671 {
1672 	if (settings.paratab_showing)
1673 		return 1;
1674 	return 0;
1675 }
1676 
_tabs_on(void)1677 static void _tabs_on(void)
1678 {
1679 	xml_set_value("Xiphos", "tabs", "browsing", "1");
1680 	settings.browsing = TRUE;
1681 	gui_close_all_tabs();
1682 	gui_load_tabs(default_tab_filename);
1683 	gtk_widget_show(widgets.hboxtb);
1684 	gtk_widget_show(widgets.hpaned);
1685 }
1686 
_tabs_off(void)1687 static void _tabs_off(void)
1688 {
1689 	int page = _is_paratab_showing();
1690 	xml_set_value("Xiphos", "tabs", "browsing", "0");
1691 	gui_save_tabs(default_tab_filename);
1692 	if (settings.showparatab) {
1693 		gui_close_passage_tab(gtk_notebook_page_num(GTK_NOTEBOOK(widgets.notebook_main),
1694 							    widgets.parallel_tab));
1695 		settings.showparatab = FALSE;
1696 	}
1697 	gui_close_all_tabs();
1698 	settings.browsing = FALSE;
1699 	gui_load_tabs(no_tab_filename);
1700 	gtk_widget_hide(widgets.hboxtb);
1701 	gtk_notebook_set_current_page(GTK_NOTEBOOK(widgets.notebook_bible_parallel),
1702 				      page);
1703 }
1704 
gui_tabs_on_off(int on)1705 void gui_tabs_on_off(int on)
1706 {
1707 	if (on)
1708 		_tabs_on();
1709 	else
1710 		_tabs_off();
1711 }
1712