1 /*
2 * Copyright (C) 2007 Ignacio Casal Quinteiro <nacho.resa@gmail.com>
3 * Fatih Demir <kabalak@kabalak.net>
4 * Ross Golder <ross@golder.org>
5 * Gediminas Paulauskas <menesis@kabalak.net>
6 * homas Ziehmer <thomas@kabalak.net>
7 * 2008 Igalia
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 *
22 * Authors:
23 * Ignacio Casal Quinteiro <nacho.resa@gmail.com>
24 * Pablo Sanxiao <psanxiao@gmail.com>
25 * Fatih Demir <kabalak@kabalak.net>
26 * Ross Golder <ross@golder.org>
27 * Gediminas Paulauskas <menesis@kabalak.net>
28 * Thomas Ziehmer <thomas@kabalak.net>
29 */
30
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34
35 #include "gtr-application.h"
36 #include "gtr-context.h"
37 #include "gtr-io-error-info-bar.h"
38 #include "gtr-message-table.h"
39 #include "gtr-msg.h"
40 #include "gtr-tab-activatable.h"
41 #include "gtr-tab.h"
42 #include "gtr-po.h"
43 #include "gtr-settings.h"
44 #include "gtr-view.h"
45 #include "gtr-dirs.h"
46 #include "gtr-debug.h"
47 #include "gtr-window.h"
48 #include "gtr-progress.h"
49 #include "gtr-actions.h"
50
51 #include <glib.h>
52 #include <glib-object.h>
53 #include <glib/gi18n.h>
54 #include <gtk/gtk.h>
55 #include <gtksourceview/gtksource.h>
56
57 #define MAX_PLURALS 6
58
59 #define GTR_TAB_KEY "GtrTabFromDocument"
60
61 typedef struct
62 {
63 GSettings *ui_settings;
64 GSettings *files_settings;
65 GSettings *editor_settings;
66 GSettings *state_settings;
67
68 GtkWidget *progress_eventbox;
69 GtkWidget *progress_box;
70 GtkWidget *progress_revealer;
71 GtkWidget *progress_percentage;
72 GtkWidget *progress_trans;
73 GtkWidget *progress_fuzzy;
74 GtkWidget *progress_untrans;
75
76 GtrProgress *progress;
77 gboolean find_replace_flag;
78
79 GtrPo *po;
80
81 GtkWidget *dock;
82
83 /*Vertical and Horizontal Panes */
84 GtkPaned *hbox;
85 GtkPaned *vertical_box;
86 gint context_position;
87 gint content_position;
88
89 GtkWidget *message_table;
90 GtkWidget *context;
91
92 /*Info bar */
93 GtkWidget *infobar;
94
95 /*Original text */
96 GtkWidget *text_msgid;
97 GtkWidget *text_plural_scroll;
98 GtkWidget *text_msgid_plural;
99 GtkWidget *msgid_tags;
100 GtkWidget *msgid_ctxt;
101
102 /*Translated text */
103 GtkWidget *msgstr_label;
104 GtkWidget *trans_notebook;
105 GtkWidget *trans_msgstr[MAX_PLURALS];
106
107 /*Status widgets */
108 GtkWidget *translated;
109 GtkWidget *fuzzy;
110 GtkWidget *untranslated;
111
112 /* Autosave */
113 GTimer *timer;
114 gint autosave_interval;
115 guint autosave_timeout;
116 guint autosave : 1;
117 /*Blocking movement */
118 guint blocking : 1;
119
120 guint tab_realized : 1;
121 guint dispose_has_run : 1;
122
123 /*Search Bar*/
124 GtkOverlay *overlay;
125 GtkRevealer *search_revealer;
126 GtrSearchBar *search_bar;
127 GtkSearchEntry *search;
128
129 } GtrTabPrivate;
130
131 G_DEFINE_TYPE_WITH_PRIVATE (GtrTab, gtr_tab, GTK_TYPE_BOX)
132
133 enum
134 {
135 SHOWED_MESSAGE,
136 MESSAGE_CHANGED,
137 MESSAGE_EDITION_FINISHED,
138 SELECTION_CHANGED,
139 LAST_SIGNAL
140 };
141
142 enum
143 {
144 PROP_0,
145 PROP_NAME,
146 PROP_AUTOSAVE,
147 PROP_AUTOSAVE_INTERVAL
148 };
149
150 static guint signals[LAST_SIGNAL];
151
152 static gboolean gtr_tab_autosave (GtrTab * tab);
153
154 //---------------------------Search Bar Revealer------------------//
155
156 void
gtr_page_stop_search(GtrTab * tab,GtrSearchBar * search_bar)157 gtr_page_stop_search (GtrTab *tab,
158 GtrSearchBar *search_bar)
159 {
160 GtrTabPrivate *priv;
161
162 priv = gtr_tab_get_instance_private (tab);
163 g_assert (GTR_IS_TAB (tab));
164 g_assert (GTR_IS_SEARCH_BAR (priv->search_bar));
165
166 gtk_revealer_set_reveal_child (priv->search_revealer, FALSE);
167
168 }
169
170 void
gtr_tab_show_hide_search_bar(GtrTab * tab,gboolean show)171 gtr_tab_show_hide_search_bar (GtrTab *tab, gboolean show)
172 {
173 GtrTabPrivate *priv;
174
175 g_assert (GTR_IS_TAB (tab));
176 priv = gtr_tab_get_instance_private (tab);
177
178 gtk_revealer_set_reveal_child (priv->search_revealer, show);
179 }
180
181 void
gtr_tab_find_set_replace(GtrTab * tab,gboolean replace)182 gtr_tab_find_set_replace (GtrTab *tab,
183 gboolean replace)
184 {
185 GtrTabPrivate *priv;
186
187 g_assert (GTR_IS_TAB (tab));
188 priv = gtr_tab_get_instance_private (tab);
189 gtr_search_bar_set_replace_mode (priv->search_bar, replace);
190 }
191
192 void
gtr_tab_find_next(GtrTab * tab)193 gtr_tab_find_next (GtrTab * tab)
194 {
195 GtrTabPrivate *priv;
196
197 priv = gtr_tab_get_instance_private (tab);
198 gtr_search_bar_find_next (priv->search_bar);
199 }
200
201 void
gtr_tab_find_prev(GtrTab * tab)202 gtr_tab_find_prev (GtrTab * tab)
203 {
204 GtrTabPrivate *priv;
205
206 priv = gtr_tab_get_instance_private (tab);
207 gtr_search_bar_find_prev (priv->search_bar);
208 }
209
210 void
gtr_page_notify_child_revealed(GtrTab * tab,GParamSpec * pspec,GtkRevealer * revealer)211 gtr_page_notify_child_revealed (GtrTab *tab,
212 GParamSpec *pspec,
213 GtkRevealer *revealer)
214 {
215 GtrTabPrivate *priv;
216
217 priv = gtr_tab_get_instance_private (tab);
218 g_assert (GTR_IS_TAB (tab));
219 g_assert (GTK_IS_REVEALER (revealer));
220
221 if (gtk_revealer_get_child_revealed (revealer))
222 {
223 GtkWidget *toplevel = gtk_widget_get_ancestor (GTK_WIDGET (revealer), GTK_TYPE_WINDOW);
224 GtkWidget *focus = gtk_window_get_focus (GTK_WINDOW (toplevel));
225
226 /* Only focus the search bar if it doesn't already have focus,
227 * as it can reselect the search text.
228 */
229 if (focus == NULL || !gtk_widget_is_ancestor (focus, GTK_WIDGET (revealer)))
230 gtk_widget_grab_focus (GTK_WIDGET (priv->search_bar));
231 }
232 }
233
234 //----------------------------------------------------------------//
235
236 static gboolean
show_hide_revealer(GtkWidget * widget,GdkEvent * ev,GtrTab * tab)237 show_hide_revealer (GtkWidget *widget, GdkEvent *ev, GtrTab *tab)
238 {
239 GtrTabPrivate *priv;
240 GtkRevealer *rev;
241
242 priv = gtr_tab_get_instance_private (tab);
243 rev = GTK_REVEALER (priv->progress_revealer);
244 gtk_revealer_set_reveal_child (rev, !gtk_revealer_get_reveal_child (rev));
245
246 return TRUE;
247 }
248
249 static gboolean
msg_grab_focus(GtrTab * tab)250 msg_grab_focus (GtrTab *tab)
251 {
252 GtrTabPrivate *priv;
253 priv = gtr_tab_get_instance_private (tab);
254 gtk_widget_grab_focus (priv->trans_msgstr[0]);
255 return FALSE;
256 }
257
258 static void
install_autosave_timeout(GtrTab * tab)259 install_autosave_timeout (GtrTab * tab)
260 {
261 GtrTabPrivate *priv;
262 gint timeout;
263
264 priv = gtr_tab_get_instance_private (tab);
265 g_return_if_fail (priv->autosave_timeout <= 0);
266 g_return_if_fail (priv->autosave);
267 g_return_if_fail (priv->autosave_interval > 0);
268
269 /* Add a new timeout */
270 timeout = g_timeout_add (priv->autosave_interval * 1000 * 60,
271 (GSourceFunc) gtr_tab_autosave, tab);
272
273 priv->autosave_timeout = timeout;
274 }
275
276 static gboolean
install_autosave_timeout_if_needed(GtrTab * tab)277 install_autosave_timeout_if_needed (GtrTab * tab)
278 {
279 GtrTabPrivate *priv;
280
281 priv = gtr_tab_get_instance_private (tab);
282 g_return_val_if_fail (priv->autosave_timeout <= 0, FALSE);
283
284 if (priv->autosave)
285 {
286 install_autosave_timeout (tab);
287
288 return TRUE;
289 }
290
291 return FALSE;
292 }
293
294 static gboolean
gtr_tab_autosave(GtrTab * tab)295 gtr_tab_autosave (GtrTab * tab)
296 {
297 GError *error = NULL;
298 GtrTabPrivate *priv;
299
300 priv = gtr_tab_get_instance_private (tab);
301 if (!(gtr_po_get_state (priv->po) == GTR_PO_STATE_MODIFIED))
302 return TRUE;
303
304 gtr_po_save_file (priv->po, &error);
305 if (error)
306 {
307 g_warning ("%s", error->message);
308 g_error_free (error);
309 }
310
311 return TRUE;
312 }
313
314 static void
remove_autosave_timeout(GtrTab * tab)315 remove_autosave_timeout (GtrTab * tab)
316 {
317 GtrTabPrivate *priv;
318
319 priv = gtr_tab_get_instance_private (tab);
320 g_return_if_fail (priv->autosave_timeout > 0);
321
322 g_source_remove (priv->autosave_timeout);
323 priv->autosave_timeout = 0;
324 }
325
326 static void
gtr_tab_edition_finished(GtrTab * tab,GtrMsg * msg)327 gtr_tab_edition_finished (GtrTab * tab, GtrMsg * msg)
328 {
329 gchar *message_error;
330 GtkWidget *infobar;
331
332 /*
333 * Checking message
334 */
335 message_error = gtr_msg_check (msg);
336
337 if (message_error != NULL)
338 {
339 gtr_tab_block_movement (tab);
340
341 infobar = create_error_info_bar (_("There is an error in the message:"),
342 message_error);
343 gtr_tab_set_info_bar (tab, infobar);
344 g_free (message_error);
345 }
346 else
347 {
348 gtr_tab_unblock_movement (tab);
349 gtr_tab_set_info_bar (tab, NULL);
350 }
351 }
352
353 /*
354 * Write the change back to the gettext PO instance in memory and
355 * mark the page dirty
356 */
357 static void
gtr_message_translation_update(GtkTextBuffer * textbuffer,GtrTab * tab)358 gtr_message_translation_update (GtkTextBuffer * textbuffer, GtrTab * tab)
359 {
360 GtrHeader *header;
361 GtkTextIter start, end;
362 GtkTextBuffer *buf;
363 GList *msg_aux;
364 GtrMsg *msg;
365 GtrTabPrivate *priv;
366 const gchar *check;
367 gchar *translation;
368 gboolean unmark_fuzzy;
369 gint i;
370
371 priv = gtr_tab_get_instance_private (tab);
372
373 /* Work out which message this is associated with */
374 header = gtr_po_get_header (priv->po);
375
376 msg_aux = gtr_po_get_current_message (priv->po);
377 msg = msg_aux->data;
378 buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->trans_msgstr[0]));
379 unmark_fuzzy = g_settings_get_boolean (priv->editor_settings,
380 GTR_SETTINGS_UNMARK_FUZZY_WHEN_CHANGED);
381
382 unmark_fuzzy = unmark_fuzzy && !priv->find_replace_flag;
383 if (gtr_msg_is_fuzzy (msg) && unmark_fuzzy)
384 gtr_msg_set_fuzzy (msg, FALSE);
385
386 if (textbuffer == buf)
387 {
388 /* Get message as UTF-8 buffer */
389 gtk_text_buffer_get_bounds (textbuffer, &start, &end);
390 translation = gtk_text_buffer_get_text (textbuffer, &start, &end, TRUE);
391
392 /* TODO: convert to file's own encoding if not UTF-8 */
393
394 /* Write back to PO file in memory */
395 if (!(check = gtr_msg_get_msgid_plural (msg)))
396 {
397 gtr_msg_set_msgstr (msg, translation);
398 }
399 else
400 {
401 gtr_msg_set_msgstr_plural (msg, 0, translation);
402 //free(check);
403 }
404 g_free (translation);
405 return;
406 }
407 i = 1;
408 while (i < gtr_header_get_nplurals (header))
409 {
410 /* Know when to break out of the loop */
411 if (!priv->trans_msgstr[i])
412 {
413 break;
414 }
415
416 /* Have we reached the one we want yet? */
417 buf =
418 gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->trans_msgstr[i]));
419 if (textbuffer != buf)
420 {
421 i++;
422 continue;
423 }
424
425 /* Get message as UTF-8 buffer */
426 gtk_text_buffer_get_bounds (textbuffer, &start, &end);
427 translation = gtk_text_buffer_get_text (textbuffer, &start, &end, TRUE);
428
429 /* TODO: convert to file's own encoding if not UTF-8 */
430
431 /* Write back to PO file in memory */
432 gtr_msg_set_msgstr_plural (msg, i, translation);
433 return;
434 }
435
436 /* Shouldn't get here */
437 g_return_if_reached ();
438 }
439
440 static GtkWidget *
gtr_tab_append_msgstr_page(const gchar * tab_label,GtkWidget * box,gboolean spellcheck,GtrTab * tab)441 gtr_tab_append_msgstr_page (const gchar * tab_label,
442 GtkWidget * box, gboolean spellcheck,
443 GtrTab *tab)
444 {
445 GtkWidget *scroll;
446 GtkWidget *label;
447 GtkWidget *widget;
448 GtrTabPrivate *priv;
449
450 label = gtk_label_new (tab_label);
451
452 scroll = gtk_scrolled_window_new (NULL, NULL);
453 gtk_widget_show (scroll);
454
455 widget = gtr_view_new ();
456 gtk_widget_show (widget);
457
458 priv = gtr_tab_get_instance_private (tab);
459
460 if (spellcheck &&
461 g_settings_get_boolean (priv->editor_settings,
462 GTR_SETTINGS_SPELLCHECK))
463 {
464 gtr_view_enable_spellcheck (GTR_VIEW (widget), spellcheck);
465 }
466
467 gtk_container_add (GTK_CONTAINER (scroll), widget);
468
469 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll),
470 GTK_SHADOW_IN);
471
472 gtk_notebook_append_page (GTK_NOTEBOOK (box), scroll, label);
473
474 return widget;
475 }
476
477 static void
gtr_message_plural_forms(GtrTab * tab,GtrMsg * msg)478 gtr_message_plural_forms (GtrTab * tab, GtrMsg * msg)
479 {
480 GtrHeader *header;
481 GtkTextBuffer *buf;
482 GtrTabPrivate *priv;
483 const gchar *msgstr_plural;
484 gint i;
485
486 g_return_if_fail (tab != NULL);
487 g_return_if_fail (msg != NULL);
488
489 priv = gtr_tab_get_instance_private (tab);
490
491 header = gtr_po_get_header (priv->po);
492
493 for (i = 0; i < gtr_header_get_nplurals (header); i++)
494 {
495 msgstr_plural = gtr_msg_get_msgstr_plural (msg, i);
496 if (msgstr_plural)
497 {
498 buf =
499 gtk_text_view_get_buffer (GTK_TEXT_VIEW
500 (priv->trans_msgstr[i]));
501 gtk_source_buffer_begin_not_undoable_action (GTK_SOURCE_BUFFER
502 (buf));
503 gtk_text_buffer_set_text (buf, (gchar *) msgstr_plural, -1);
504 gtk_source_buffer_end_not_undoable_action (GTK_SOURCE_BUFFER (buf));
505 }
506 }
507 }
508
509 /*
510 * gtr_tab_show_message:
511 * @tab: a #GtranslationTab
512 * @msg: a #GtrMsg
513 *
514 * Shows the @msg in the @tab TextViews
515 *
516 */
517 static void
gtr_tab_show_message(GtrTab * tab,GtrMsg * msg)518 gtr_tab_show_message (GtrTab * tab, GtrMsg * msg)
519 {
520 GtrTabPrivate *priv;
521 GtrPo *po;
522 GtkTextBuffer *buf;
523 const gchar *msgid, *msgid_plural;
524 const gchar *msgstr;
525 const gchar *msgctxt;
526
527 g_return_if_fail (GTR_IS_TAB (tab));
528
529 priv = gtr_tab_get_instance_private (tab);
530 gtk_label_set_text (GTK_LABEL (priv->msgid_tags), "");
531
532 msgctxt = gtr_msg_get_msgctxt (msg);
533 if (msgctxt)
534 {
535 gtk_label_set_text (GTK_LABEL (priv->msgid_ctxt), msgctxt);
536 gtk_widget_show (priv->msgid_ctxt);
537 }
538 else
539 {
540 gtk_widget_hide (priv->msgid_ctxt);
541 }
542
543 po = priv->po;
544 gtr_po_update_current_message (po, msg);
545 msgid = gtr_msg_get_msgid (msg);
546 if (msgid)
547 {
548 gchar *msg_error = gtr_msg_check (msg);
549 buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->text_msgid));
550 gtk_source_buffer_begin_not_undoable_action (GTK_SOURCE_BUFFER (buf));
551 gtk_text_buffer_set_text (buf, (gchar *) msgid, -1);
552 gtk_source_buffer_end_not_undoable_action (GTK_SOURCE_BUFFER (buf));
553
554 if (gtr_msg_is_fuzzy (msg))
555 gtk_label_set_text (GTK_LABEL (priv->msgid_tags), _("fuzzy"));
556 if (msg_error) {
557 gtk_label_set_text (GTK_LABEL (priv->msgid_tags), msg_error);
558 g_free (msg_error);
559 }
560 }
561 msgid_plural = gtr_msg_get_msgid_plural (msg);
562 if (!msgid_plural)
563 {
564 msgstr = gtr_msg_get_msgstr (msg);
565 /*
566 * Disable notebook tabs and hide widgets
567 */
568 gtk_widget_hide (priv->text_plural_scroll);
569 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->trans_notebook), FALSE);
570 gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->trans_notebook), 0);
571 if (msgstr)
572 {
573 buf =
574 gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->trans_msgstr[0]));
575 gtk_source_buffer_begin_not_undoable_action (GTK_SOURCE_BUFFER
576 (buf));
577 gtk_text_buffer_set_text (buf, (gchar *) msgstr, -1);
578 gtk_source_buffer_end_not_undoable_action (GTK_SOURCE_BUFFER (buf));
579 gtk_label_set_mnemonic_widget (GTK_LABEL (priv->msgstr_label),
580 priv->trans_msgstr[0]);
581 }
582 }
583 else
584 {
585 gtk_widget_show (priv->text_plural_scroll);
586 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->trans_notebook),
587 TRUE);
588 buf =
589 gtk_text_view_get_buffer (GTK_TEXT_VIEW
590 (priv->text_msgid_plural));
591 gtk_text_buffer_set_text (buf, (gchar *) msgid_plural, -1);
592 gtr_message_plural_forms (tab, msg);
593 }
594 }
595
596 static void
emit_message_changed_signal(GtkTextBuffer * buf,GtrTab * tab)597 emit_message_changed_signal (GtkTextBuffer * buf, GtrTab * tab)
598 {
599 GList *msg;
600 GtrTabPrivate *priv;
601
602 priv = gtr_tab_get_instance_private (tab);
603 msg = gtr_po_get_current_message (priv->po);
604
605 g_signal_emit (G_OBJECT (tab), signals[MESSAGE_CHANGED], 0, msg->data);
606 }
607
608 static void
emit_selection_changed(GtkTextBuffer * buf,GParamSpec * spec,GtrTab * tab)609 emit_selection_changed (GtkTextBuffer * buf, GParamSpec * spec, GtrTab * tab)
610 {
611 g_signal_emit (G_OBJECT (tab), signals[SELECTION_CHANGED], 0);
612 }
613
614 static void
update_status(GtrTab * tab,GtrMsg * msg,gpointer useless)615 update_status (GtrTab * tab, GtrMsg * msg, gpointer useless)
616 {
617 GtrMsgStatus status;
618 GtrPoState po_state;
619 GtrTabPrivate *priv;
620 gboolean fuzzy, translated;
621 gchar *msg_error = NULL;
622
623 priv = gtr_tab_get_instance_private (tab);
624
625 status = gtr_msg_get_status (msg);
626 po_state = gtr_po_get_state (priv->po);
627
628 fuzzy = gtr_msg_is_fuzzy (msg);
629 translated = gtr_msg_is_translated (msg);
630
631 if ((status == GTR_MSG_STATUS_FUZZY) && !fuzzy && !priv->find_replace_flag)
632 {
633 _gtr_po_increase_decrease_fuzzy (priv->po, FALSE);
634 if (translated)
635 {
636 status = GTR_MSG_STATUS_TRANSLATED;
637 _gtr_po_increase_decrease_translated (priv->po, TRUE);
638 }
639 else
640 {
641 status = GTR_MSG_STATUS_UNTRANSLATED;
642 }
643 }
644 else if ((status == GTR_MSG_STATUS_TRANSLATED) && !translated)
645 {
646 status = GTR_MSG_STATUS_UNTRANSLATED;
647 _gtr_po_increase_decrease_translated (priv->po, FALSE);
648 }
649 else if ((status == GTR_MSG_STATUS_TRANSLATED) && fuzzy)
650 {
651 status = GTR_MSG_STATUS_FUZZY;
652 _gtr_po_increase_decrease_translated (priv->po, FALSE);
653 _gtr_po_increase_decrease_fuzzy (priv->po, TRUE);
654 }
655 else if ((status == GTR_MSG_STATUS_UNTRANSLATED) && translated)
656 {
657 if (fuzzy)
658 {
659 status = GTR_MSG_STATUS_FUZZY;
660 _gtr_po_increase_decrease_fuzzy (priv->po, TRUE);
661 }
662 else
663 {
664 status = GTR_MSG_STATUS_TRANSLATED;
665 _gtr_po_increase_decrease_translated (priv->po, TRUE);
666 }
667 }
668
669 if (status != gtr_msg_get_status (msg))
670 {
671 gtr_msg_set_status (msg, status);
672 g_signal_emit (G_OBJECT (tab), signals[MESSAGE_CHANGED], 0, msg);
673 }
674
675 msg_error = gtr_msg_check (msg);
676 if (msg_error) {
677 gtk_label_set_text (GTK_LABEL (priv->msgid_tags), msg_error);
678 g_free (msg_error);
679 }
680 else if (gtr_msg_is_fuzzy (msg))
681 gtk_label_set_text (GTK_LABEL (priv->msgid_tags), _("fuzzy"));
682 else
683 gtk_label_set_text (GTK_LABEL (priv->msgid_tags), "");
684
685 /* We need to update the tab state too if is neccessary */
686 if (po_state != GTR_PO_STATE_MODIFIED)
687 gtr_po_set_state (priv->po, GTR_PO_STATE_MODIFIED);
688 }
689
690 static void
gtr_tab_add_msgstr_tabs(GtrTab * tab)691 gtr_tab_add_msgstr_tabs (GtrTab * tab)
692 {
693 GtrHeader *header;
694 GtrTabPrivate *priv;
695 gchar *label;
696 GtkTextBuffer *buf;
697 gint i = 0;
698 gchar *lang_code = NULL;
699
700 priv = gtr_tab_get_instance_private (tab);
701
702 /*
703 * We get the header of the po file
704 */
705 header = gtr_po_get_header (priv->po);
706 lang_code = gtr_header_get_language_code (header);
707
708 do
709 {
710
711 label = g_strdup_printf (_("Plural %d"), i);
712 priv->trans_msgstr[i] = gtr_tab_append_msgstr_page (label,
713 priv->trans_notebook,
714 TRUE,
715 tab);
716
717 gtr_view_set_language (GTR_VIEW (priv->trans_msgstr[i]), lang_code);
718
719 buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->trans_msgstr[i]));
720 g_signal_connect (buf, "end-user-action",
721 G_CALLBACK (gtr_message_translation_update), tab);
722
723 g_signal_connect_after (buf, "end_user_action",
724 G_CALLBACK (emit_message_changed_signal), tab);
725 g_signal_connect (buf, "notify::has-selection",
726 G_CALLBACK (emit_selection_changed), tab);
727 i++;
728 g_free (label);
729 }
730 while (i < gtr_header_get_nplurals (header));
731 g_free (lang_code);
732 }
733
734 static void
on_location_notify(GtrPo * po,GParamSpec * pspec,GtrTab * tab)735 on_location_notify (GtrPo *po,
736 GParamSpec *pspec,
737 GtrTab *tab)
738 {
739 g_object_notify (G_OBJECT (tab), "name");
740 }
741
742 static void
on_state_notify(GtrPo * po,GParamSpec * pspec,GtrTab * tab)743 on_state_notify (GtrPo *po,
744 GParamSpec *pspec,
745 GtrTab *tab)
746 {
747 g_object_notify (G_OBJECT (tab), "name");
748 }
749
750 static void
gtr_tab_init(GtrTab * tab)751 gtr_tab_init (GtrTab * tab)
752 {
753 GtrTabPrivate *priv;
754
755 priv = gtr_tab_get_instance_private (tab);
756
757 gtk_widget_init_template (GTK_WIDGET (tab));
758
759 priv->ui_settings = g_settings_new ("org.gnome.gtranslator.preferences.ui");
760 priv->files_settings = g_settings_new ("org.gnome.gtranslator.preferences.files");
761 priv->editor_settings = g_settings_new ("org.gnome.gtranslator.preferences.editor");
762 priv->state_settings = g_settings_new ("org.gnome.gtranslator.state.window");
763
764 g_signal_connect (tab, "message-changed", G_CALLBACK (update_status), NULL);
765
766 /*Load gsettings for panes */
767 priv->context_position = g_settings_get_int (priv->state_settings,
768 GTR_SETTINGS_CONTEXT_PANEL_SIZE);
769
770 priv->content_position = g_settings_get_int (priv->state_settings,
771 GTR_SETTINGS_CONTENT_PANEL_SIZE);
772
773 gtk_paned_set_position (priv->hbox, priv->context_position);
774 gtk_paned_set_position (priv->vertical_box, priv->content_position);
775
776 /* Manage auto save data */
777 priv->autosave = g_settings_get_boolean (priv->files_settings,
778 GTR_SETTINGS_AUTO_SAVE);
779 priv->autosave = (priv->autosave != FALSE);
780
781 priv->autosave_interval = g_settings_get_int (priv->files_settings,
782 GTR_SETTINGS_AUTO_SAVE_INTERVAL);
783 if (priv->autosave_interval <= 0)
784 priv->autosave_interval = 1;
785
786 priv->find_replace_flag = FALSE;
787 priv->progress = gtr_progress_new ();
788 gtk_widget_show (GTK_WIDGET (priv->progress));
789 gtk_container_add (GTK_CONTAINER (priv->progress_box), GTK_WIDGET (priv->progress));
790
791 g_signal_connect (priv->progress_eventbox, "button-press-event",
792 G_CALLBACK (show_hide_revealer), tab);
793 }
794
795 static void
gtr_tab_finalize(GObject * object)796 gtr_tab_finalize (GObject * object)
797 {
798 GtrTab *tab = GTR_TAB (object);
799 GtrTabPrivate *priv;
800
801 priv = gtr_tab_get_instance_private (tab);
802
803 if (priv->timer != NULL)
804 g_timer_destroy (priv->timer);
805
806 if (priv->autosave_timeout > 0)
807 remove_autosave_timeout (tab);
808
809 G_OBJECT_CLASS (gtr_tab_parent_class)->finalize (object);
810 }
811
812 static void
save_pane_state(GtrTab * tab)813 save_pane_state(GtrTab *tab)
814 {
815 GtrTabPrivate *priv;
816
817 priv = gtr_tab_get_instance_private (tab);
818
819 priv->context_position = gtk_paned_get_position (priv->hbox);
820 priv->content_position = gtk_paned_get_position (priv->vertical_box);
821
822 g_settings_set_int (priv->state_settings, GTR_SETTINGS_CONTEXT_PANEL_SIZE,
823 priv->context_position);
824
825 g_settings_set_int (priv->state_settings, GTR_SETTINGS_CONTENT_PANEL_SIZE,
826 priv->content_position);
827 }
828
829 static void
gtr_tab_dispose(GObject * object)830 gtr_tab_dispose (GObject * object)
831 {
832 GtrTab *tab = GTR_TAB(object);
833 GtrTabPrivate *priv;
834
835 priv = gtr_tab_get_instance_private (GTR_TAB (object));
836
837 if (!priv->dispose_has_run)
838 {
839 save_pane_state (tab);
840 priv->dispose_has_run = TRUE;
841 }
842
843 g_clear_object (&priv->po);
844 g_clear_object (&priv->ui_settings);
845 g_clear_object (&priv->files_settings);
846 g_clear_object (&priv->editor_settings);
847 g_clear_object (&priv->state_settings);
848
849 G_OBJECT_CLASS (gtr_tab_parent_class)->dispose (object);
850 }
851
852 static void
gtr_tab_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)853 gtr_tab_get_property (GObject * object,
854 guint prop_id, GValue * value, GParamSpec * pspec)
855 {
856 GtrTab *tab = GTR_TAB (object);
857
858 switch (prop_id)
859 {
860 case PROP_AUTOSAVE:
861 g_value_set_boolean (value, gtr_tab_get_autosave_enabled (tab));
862 break;
863 case PROP_AUTOSAVE_INTERVAL:
864 g_value_set_int (value, gtr_tab_get_autosave_interval (tab));
865 break;
866 default:
867 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
868 break;
869 }
870 }
871
872 static void
gtr_tab_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)873 gtr_tab_set_property (GObject * object,
874 guint prop_id, const GValue * value, GParamSpec * pspec)
875 {
876 GtrTab *tab = GTR_TAB (object);
877
878 switch (prop_id)
879 {
880 case PROP_AUTOSAVE:
881 gtr_tab_set_autosave_enabled (tab, g_value_get_boolean (value));
882 break;
883 case PROP_AUTOSAVE_INTERVAL:
884 gtr_tab_set_autosave_interval (tab, g_value_get_int (value));
885 break;
886 default:
887 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
888 break;
889 }
890 }
891
892 static void
gtr_tab_realize(GtkWidget * widget)893 gtr_tab_realize (GtkWidget *widget)
894 {
895 GTK_WIDGET_CLASS (gtr_tab_parent_class)->realize (widget);
896 }
897
898 static void
gtr_tab_class_init(GtrTabClass * klass)899 gtr_tab_class_init (GtrTabClass * klass)
900 {
901 GObjectClass *object_class = G_OBJECT_CLASS (klass);
902 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
903
904 object_class->finalize = gtr_tab_finalize;
905 object_class->dispose = gtr_tab_dispose;
906 object_class->set_property = gtr_tab_set_property;
907 object_class->get_property = gtr_tab_get_property;
908
909 widget_class->realize = gtr_tab_realize;
910
911 klass->message_edition_finished = gtr_tab_edition_finished;
912
913 /* Signals */
914 signals[SHOWED_MESSAGE] =
915 g_signal_new ("showed-message",
916 G_OBJECT_CLASS_TYPE (klass),
917 G_SIGNAL_RUN_LAST,
918 G_STRUCT_OFFSET (GtrTabClass, showed_message),
919 NULL, NULL,
920 g_cclosure_marshal_VOID__OBJECT,
921 G_TYPE_NONE, 1, GTR_TYPE_MSG);
922
923 signals[MESSAGE_CHANGED] =
924 g_signal_new ("message-changed",
925 G_OBJECT_CLASS_TYPE (klass),
926 G_SIGNAL_RUN_LAST,
927 G_STRUCT_OFFSET (GtrTabClass, message_changed),
928 NULL, NULL,
929 g_cclosure_marshal_VOID__OBJECT,
930 G_TYPE_NONE, 1, GTR_TYPE_MSG);
931
932 signals[MESSAGE_EDITION_FINISHED] =
933 g_signal_new ("message-edition-finished",
934 G_OBJECT_CLASS_TYPE (klass),
935 G_SIGNAL_RUN_LAST,
936 G_STRUCT_OFFSET (GtrTabClass, message_edition_finished),
937 NULL, NULL,
938 g_cclosure_marshal_VOID__OBJECT,
939 G_TYPE_NONE, 1, GTR_TYPE_MSG);
940 signals[SELECTION_CHANGED] =
941 g_signal_new ("selection-changed",
942 G_OBJECT_CLASS_TYPE (klass),
943 G_SIGNAL_RUN_LAST,
944 G_STRUCT_OFFSET (GtrTabClass, selection_changed),
945 NULL, NULL,
946 g_cclosure_marshal_VOID__VOID,
947 G_TYPE_NONE, 0);
948
949 /* Properties */
950 g_object_class_install_property (object_class,
951 PROP_NAME,
952 g_param_spec_string ("name",
953 "Name",
954 "The tab's name",
955 NULL,
956 G_PARAM_READABLE |
957 G_PARAM_STATIC_STRINGS));
958
959 g_object_class_install_property (object_class,
960 PROP_AUTOSAVE,
961 g_param_spec_boolean ("autosave",
962 "Autosave",
963 "Autosave feature",
964 TRUE,
965 G_PARAM_READWRITE |
966 G_PARAM_STATIC_STRINGS));
967
968 g_object_class_install_property (object_class,
969 PROP_AUTOSAVE_INTERVAL,
970 g_param_spec_int ("autosave-interval",
971 "AutosaveInterval",
972 "Time between two autosaves",
973 0,
974 G_MAXINT,
975 0,
976 G_PARAM_READWRITE |
977 G_PARAM_STATIC_STRINGS));
978
979 gtk_widget_class_set_template_from_resource (widget_class,
980 "/org/gnome/translator/gtr-tab.ui");
981
982 gtk_widget_class_bind_template_child_private (widget_class, GtrTab, message_table);
983 gtk_widget_class_bind_template_child_private (widget_class, GtrTab, text_msgid);
984 gtk_widget_class_bind_template_child_private (widget_class, GtrTab, msgid_tags);
985 gtk_widget_class_bind_template_child_private (widget_class, GtrTab, msgid_ctxt);
986 gtk_widget_class_bind_template_child_private (widget_class, GtrTab, text_plural_scroll);
987 gtk_widget_class_bind_template_child_private (widget_class, GtrTab, text_msgid_plural);
988 gtk_widget_class_bind_template_child_private (widget_class, GtrTab, msgstr_label);
989 gtk_widget_class_bind_template_child_private (widget_class, GtrTab, trans_notebook);
990 gtk_widget_class_bind_template_child_private (widget_class, GtrTab, context);
991 gtk_widget_class_bind_template_child_private (widget_class, GtrTab, hbox);
992 gtk_widget_class_bind_template_child_private (widget_class, GtrTab, vertical_box);
993
994 gtk_widget_class_bind_template_child_private (widget_class, GtrTab, progress_eventbox);
995 gtk_widget_class_bind_template_child_private (widget_class, GtrTab, progress_box);
996 gtk_widget_class_bind_template_child_private (widget_class, GtrTab, progress_revealer);
997 gtk_widget_class_bind_template_child_private (widget_class, GtrTab, progress_trans);
998 gtk_widget_class_bind_template_child_private (widget_class, GtrTab, progress_fuzzy);
999 gtk_widget_class_bind_template_child_private (widget_class, GtrTab, progress_untrans);
1000 gtk_widget_class_bind_template_child_private (widget_class, GtrTab, progress_percentage);
1001 gtk_widget_class_bind_template_child_private (widget_class, GtrTab, overlay);
1002 gtk_widget_class_bind_template_child_private (widget_class, GtrTab, search_bar);
1003 gtk_widget_class_bind_template_child_private (widget_class, GtrTab, search_revealer);
1004 gtk_widget_class_bind_template_callback (widget_class, gtr_page_notify_child_revealed);
1005 gtk_widget_class_bind_template_callback (widget_class, gtr_page_stop_search);
1006
1007 g_type_ensure (gtr_view_get_type ());
1008 g_type_ensure (gtr_context_panel_get_type ());
1009 g_type_ensure (gtr_message_table_get_type ());
1010 g_type_ensure (gtr_search_bar_get_type ());
1011 }
1012
1013 /***************************** Public funcs ***********************************/
1014
1015 /**
1016 * gtr_tab_new:
1017 * @po: a #GtrPo
1018 * @window: a #GtkWindow
1019 *
1020 * Creates a new #GtrTab.
1021 *
1022 * Return value: a new #GtrTab object
1023 **/
1024 GtrTab *
gtr_tab_new(GtrPo * po,GtkWindow * window)1025 gtr_tab_new (GtrPo * po,
1026 GtkWindow *window)
1027 {
1028 GtrTab *tab;
1029 GtrTabPrivate *priv;
1030
1031 g_return_val_if_fail (po != NULL, NULL);
1032
1033 tab = g_object_new (GTR_TYPE_TAB, NULL);
1034
1035 priv = gtr_tab_get_instance_private (tab);
1036 gtr_context_init_tm (GTR_CONTEXT_PANEL (priv->context),
1037 gtr_window_get_tm (GTR_WINDOW (window)));
1038
1039 /* FIXME: make the po a property */
1040 priv->po = po;
1041 g_object_set_data (G_OBJECT (po), GTR_TAB_KEY, tab);
1042
1043 g_signal_connect (po, "notify::location",
1044 G_CALLBACK (on_location_notify), tab);
1045
1046 g_signal_connect (po, "notify::state",
1047 G_CALLBACK (on_state_notify), tab);
1048
1049 install_autosave_timeout_if_needed (tab);
1050
1051 /* Now we have to initialize the number of msgstr tabs */
1052 gtr_tab_add_msgstr_tabs (tab);
1053
1054 gtr_message_table_populate (GTR_MESSAGE_TABLE (priv->message_table),
1055 GTR_MESSAGE_CONTAINER (priv->po));
1056
1057 gtk_widget_show (GTK_WIDGET (tab));
1058 return tab;
1059 }
1060
1061 /**
1062 * gtr_tab_get_po:
1063 * @tab: a #GtrTab
1064 *
1065 * Return value: (transfer none): the #GtrPo stored in the #GtrTab
1066 **/
1067 GtrPo *
gtr_tab_get_po(GtrTab * tab)1068 gtr_tab_get_po (GtrTab * tab)
1069 {
1070 GtrTabPrivate *priv;
1071
1072 priv = gtr_tab_get_instance_private (tab);
1073 return priv->po;
1074 }
1075
1076 /**
1077 * gtr_tab_get_active_trans_tab:
1078 * @tab: a #GtranslationTab
1079 *
1080 * Return value: the number of the active translation notebook.
1081 **/
1082 gint
gtr_tab_get_active_trans_tab(GtrTab * tab)1083 gtr_tab_get_active_trans_tab (GtrTab * tab)
1084 {
1085 GtrTabPrivate *priv;
1086
1087 priv = gtr_tab_get_instance_private (tab);
1088 return
1089 gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->trans_notebook));
1090 }
1091
1092 /**
1093 * gtr_tab_get_context_panel:
1094 * @tab: a #GtrTab
1095 *
1096 * Return value: (transfer none): the #GtranslaorContextPanel
1097 */
1098 GtrContextPanel *
gtr_tab_get_context_panel(GtrTab * tab)1099 gtr_tab_get_context_panel (GtrTab * tab)
1100 {
1101 GtrTabPrivate *priv;
1102
1103 priv = gtr_tab_get_instance_private (tab);
1104 return GTR_CONTEXT_PANEL (priv->context);
1105 }
1106
1107 /**
1108 * gtr_tab_get_active_view:
1109 * @tab: a #GtranslationTab
1110 *
1111 * Return value: (transfer none): the active page of the translation notebook.
1112 **/
1113 GtrView *
gtr_tab_get_active_view(GtrTab * tab)1114 gtr_tab_get_active_view (GtrTab * tab)
1115 {
1116 GtrTabPrivate *priv;
1117 gint num;
1118
1119 priv = gtr_tab_get_instance_private (tab);
1120
1121 num =
1122 gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->trans_notebook));
1123 return GTR_VIEW (priv->trans_msgstr[num]);
1124 }
1125
1126 /**
1127 * gtr_tab_get_all_views:
1128 * @tab: the #GtranslationTab
1129 * @original: TRUE if you want original TextViews.
1130 * @translated: TRUE if you want tranlated TextViews.
1131 *
1132 * Returns all the views currently present in #GtranslationTab
1133 *
1134 * Returns: (transfer container) (element-type Gtranslator.View):
1135 * a newly allocated list of #GtranslationTab objects
1136 */
1137 GList *
gtr_tab_get_all_views(GtrTab * tab,gboolean original,gboolean translated)1138 gtr_tab_get_all_views (GtrTab * tab, gboolean original, gboolean translated)
1139 {
1140 GList *ret = NULL;
1141 GtrTabPrivate *priv;
1142 gint i = 0;
1143
1144 g_return_val_if_fail (GTR_IS_TAB (tab), NULL);
1145
1146 priv = gtr_tab_get_instance_private (tab);
1147 if (original)
1148 {
1149 ret = g_list_append (ret, priv->text_msgid);
1150 ret = g_list_append (ret, priv->text_msgid_plural);
1151 }
1152
1153 if (translated)
1154 {
1155 while (i < MAX_PLURALS)
1156 {
1157 if (priv->trans_msgstr[i])
1158 ret = g_list_append (ret, priv->trans_msgstr[i]);
1159 else
1160 break;
1161 i++;
1162 }
1163 }
1164
1165 return ret;
1166 }
1167
1168 /**
1169 * gtr_tab_message_go_to:
1170 * @tab: a #GtrTab
1171 * @to_go: the #GtrMsg you want to jump
1172 * @searching: TRUE if we are searching in the message list
1173 *
1174 * Jumps to the specific @to_go pointer message and show the message
1175 * in the #GtrView.
1176 **/
1177 void
gtr_tab_message_go_to(GtrTab * tab,GtrMsg * to_go,gboolean searching,GtrTabMove move)1178 gtr_tab_message_go_to (GtrTab * tab,
1179 GtrMsg * to_go, gboolean searching, GtrTabMove move)
1180 {
1181 static gboolean first_msg = TRUE;
1182 GtrTabPrivate *priv;
1183
1184 g_return_if_fail (tab != NULL);
1185 g_return_if_fail (GTR_IS_MSG (to_go));
1186
1187 priv = gtr_tab_get_instance_private (tab);
1188
1189 if (!priv->blocking || first_msg)
1190 {
1191 gboolean plurals;
1192 gint current_page, n_pages;
1193 /*
1194 * If the current message is plural and we press next/prev
1195 * we have to change to the next/prev plural tab in case is not
1196 * the last
1197 * To implement that:
1198 * if the tabs are showed then we check if we want prev or
1199 * next and then if we need to change the tab we change it
1200 * in other case we show the message
1201 *
1202 * I don't like too much this implementation so if anybody can
1203 * rewrite this is a better way would be great.
1204 */
1205 plurals =
1206 gtk_notebook_get_show_tabs (GTK_NOTEBOOK (priv->trans_notebook));
1207 current_page =
1208 gtk_notebook_get_current_page (GTK_NOTEBOOK
1209 (priv->trans_notebook));
1210 n_pages =
1211 gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->trans_notebook));
1212 if ((plurals == TRUE) && (move != GTR_TAB_MOVE_NONE))
1213 {
1214 if ((n_pages - 1) == current_page && move == GTR_TAB_MOVE_NEXT)
1215 {
1216 gtk_notebook_set_current_page (GTK_NOTEBOOK
1217 (priv->trans_notebook), 0);
1218 gtr_tab_show_message (tab, to_go);
1219 }
1220 else if (current_page == 0 && move == GTR_TAB_MOVE_PREV)
1221 {
1222 gtk_notebook_set_current_page (GTK_NOTEBOOK
1223 (priv->trans_notebook),
1224 n_pages - 1);
1225 gtr_tab_show_message (tab, to_go);
1226 }
1227 else
1228 {
1229 if (move == GTR_TAB_MOVE_NEXT)
1230 gtk_notebook_set_current_page (GTK_NOTEBOOK
1231 (priv->trans_notebook),
1232 current_page + 1);
1233 else
1234 gtk_notebook_set_current_page (GTK_NOTEBOOK
1235 (priv->trans_notebook),
1236 current_page - 1);
1237 return;
1238 }
1239 }
1240 else
1241 gtr_tab_show_message (tab, to_go);
1242 first_msg = FALSE;
1243 }
1244 else
1245 return;
1246
1247 // Grabbing the focus in the GtrView to edit the message
1248 // This is done in the idle add to avoid the focus grab from the
1249 // message-table
1250 g_idle_add((GSourceFunc)msg_grab_focus, tab);
1251
1252 /*
1253 * Emitting showed-message signal
1254 */
1255 if (!searching)
1256 g_signal_emit (G_OBJECT (tab), signals[SHOWED_MESSAGE], 0,
1257 GTR_MSG (to_go));
1258 }
1259
1260 /**
1261 * _gtr_tab_get_name:
1262 * @tab: a #GtrTab
1263 *
1264 * Return value: a new allocated string with the name of the @tab.
1265 */
1266 gchar *
_gtr_tab_get_name(GtrTab * tab)1267 _gtr_tab_get_name (GtrTab *tab)
1268 {
1269 GtrHeader *header;
1270 GtrPoState state;
1271 GtrTabPrivate *priv;
1272 const gchar *str;
1273 gchar *tab_name;
1274
1275 priv = gtr_tab_get_instance_private (tab);
1276
1277 header = gtr_po_get_header (priv->po);
1278 state = gtr_po_get_state (priv->po);
1279
1280 str = gtr_header_get_prj_id_version (header);
1281
1282 if (state == GTR_PO_STATE_MODIFIED)
1283 {
1284 tab_name = g_strdup_printf ("*%s", str);
1285 return tab_name;
1286 }
1287
1288 return g_strdup (str);
1289 }
1290
1291 gchar *
_gtr_tab_get_tooltips(GtrTab * tab)1292 _gtr_tab_get_tooltips (GtrTab *tab)
1293 {
1294 GFile *location;
1295 GtrTabPrivate *priv;
1296 gchar *tooltips;
1297 gchar *path;
1298
1299 priv = gtr_tab_get_instance_private (tab);
1300
1301 location = gtr_po_get_location (priv->po);
1302 path = g_file_get_path (location);
1303 g_object_unref (location);
1304
1305 /* Translators: Path to the document opened */
1306 tooltips = g_strdup_printf ("<b>%s</b> %s", _("Path:"), path);
1307 g_free (path);
1308
1309 return tooltips;
1310 }
1311
1312 /**
1313 * _gtr_tab_can_close:
1314 * @tab: a #GtrTab
1315 *
1316 * Whether a #GtrTab can be closed.
1317 *
1318 * Returns: TRUE if the #GtrPo of the @tab is already saved
1319 */
1320 gboolean
_gtr_tab_can_close(GtrTab * tab)1321 _gtr_tab_can_close (GtrTab * tab)
1322 {
1323 GtrTabPrivate *priv;
1324
1325 priv = gtr_tab_get_instance_private (tab);
1326 return gtr_po_get_state (priv->po) == GTR_PO_STATE_SAVED;
1327 }
1328
1329 /**
1330 * gtr_tab_get_from_document:
1331 * @po: a #GtrPo
1332 *
1333 * Returns the #GtrTab for a specific #GtrPo.
1334 *
1335 * Returns: (transfer none): the #GtrTab for a specific #GtrPo
1336 */
1337 GtrTab *
gtr_tab_get_from_document(GtrPo * po)1338 gtr_tab_get_from_document (GtrPo * po)
1339 {
1340 gpointer res;
1341
1342 g_return_val_if_fail (GTR_IS_PO (po), NULL);
1343
1344 res = g_object_get_data (G_OBJECT (po), GTR_TAB_KEY);
1345
1346 return (res != NULL) ? GTR_TAB (res) : NULL;
1347 }
1348
1349 /**
1350 * gtr_tab_get_autosave_enabled:
1351 * @tab: a #GtrTab
1352 *
1353 * Gets the current state for the autosave feature
1354 *
1355 * Return value: TRUE if the autosave is enabled, else FALSE
1356 **/
1357 gboolean
gtr_tab_get_autosave_enabled(GtrTab * tab)1358 gtr_tab_get_autosave_enabled (GtrTab * tab)
1359 {
1360 GtrTabPrivate *priv;
1361
1362 g_return_val_if_fail (GTR_IS_TAB (tab), FALSE);
1363
1364 priv = gtr_tab_get_instance_private (tab);
1365 return priv->autosave;
1366 }
1367
1368 /**
1369 * gtr_tab_set_autosave_enabled:
1370 * @tab: a #GtrTab
1371 * @enable: enable (TRUE) or disable (FALSE) auto save
1372 *
1373 * Enables or disables the autosave feature. It does not install an
1374 * autosave timeout if the document is new or is read-only
1375 **/
1376 void
gtr_tab_set_autosave_enabled(GtrTab * tab,gboolean enable)1377 gtr_tab_set_autosave_enabled (GtrTab * tab, gboolean enable)
1378 {
1379 GtrTabPrivate *priv;
1380
1381 g_return_if_fail (GTR_IS_TAB (tab));
1382
1383 priv = gtr_tab_get_instance_private (tab);
1384
1385 if (priv->autosave == enable)
1386 return;
1387
1388 priv->autosave = enable;
1389
1390 if (enable && (priv->autosave_timeout <= 0))
1391 {
1392 install_autosave_timeout (tab);
1393
1394 return;
1395 }
1396
1397 if (!enable && (priv->autosave_timeout > 0))
1398 {
1399 remove_autosave_timeout (tab);
1400
1401 return;
1402 }
1403
1404 g_return_if_fail (!enable && (priv->autosave_timeout <= 0));
1405 }
1406
1407 /**
1408 * gtr_tab_get_autosave_interval:
1409 * @tab: a #GtrTab
1410 *
1411 * Gets the current interval for the autosaves
1412 *
1413 * Return value: the value of the autosave
1414 **/
1415 gint
gtr_tab_get_autosave_interval(GtrTab * tab)1416 gtr_tab_get_autosave_interval (GtrTab * tab)
1417 {
1418 GtrTabPrivate *priv;
1419
1420 g_return_val_if_fail (GTR_IS_TAB (tab), 0);
1421
1422 priv = gtr_tab_get_instance_private (tab);
1423 return priv->autosave_interval;
1424 }
1425
1426 /**
1427 * gtr_tab_set_autosave_interval:
1428 * @tab: a #GtrTab
1429 * @interval: the new interval
1430 *
1431 * Sets the interval for the autosave feature. It does nothing if the
1432 * interval is the same as the one already present. It removes the old
1433 * interval timeout and adds a new one with the autosave passed as
1434 * argument.
1435 **/
1436 void
gtr_tab_set_autosave_interval(GtrTab * tab,gint interval)1437 gtr_tab_set_autosave_interval (GtrTab * tab, gint interval)
1438 {
1439 GtrTabPrivate *priv;
1440
1441 g_return_if_fail (GTR_IS_TAB (tab));
1442 g_return_if_fail (interval > 0);
1443
1444 priv = gtr_tab_get_instance_private (tab);
1445
1446 if (priv->autosave_interval == interval)
1447 return;
1448
1449 priv->autosave_interval = interval;
1450
1451 if (!priv->autosave)
1452 return;
1453
1454 if (priv->autosave_timeout > 0)
1455 {
1456 remove_autosave_timeout (tab);
1457
1458 install_autosave_timeout (tab);
1459 }
1460 }
1461
1462 /**
1463 * gtr_tab_clear_msgstr_views:
1464 * @tab: a #GtrTab
1465 *
1466 * Clears all text from msgstr text views.
1467 */
1468 void
gtr_tab_clear_msgstr_views(GtrTab * tab)1469 gtr_tab_clear_msgstr_views (GtrTab * tab)
1470 {
1471 gint i = 0;
1472 GtrHeader *header;
1473 GtkTextBuffer *buf;
1474 GtrTabPrivate *priv;
1475
1476 g_return_if_fail (GTR_IS_TAB (tab));
1477
1478 priv = gtr_tab_get_instance_private (tab);
1479
1480 header = gtr_po_get_header (priv->po);
1481
1482 do
1483 {
1484 buf =
1485 gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->trans_msgstr[i]));
1486 gtk_text_buffer_begin_user_action (buf);
1487 gtk_text_buffer_set_text (buf, "", -1);
1488 gtk_text_buffer_end_user_action (buf);
1489 i++;
1490 }
1491 while (i < gtr_header_get_nplurals (header));
1492 }
1493
1494 /**
1495 * gtr_tab_copy_to_translation:
1496 * @tab: a #GtrTab
1497 *
1498 * Copies the text from the original text box to the translation text box.
1499 */
1500 void
gtr_tab_copy_to_translation(GtrTab * tab)1501 gtr_tab_copy_to_translation (GtrTab * tab)
1502 {
1503 GtkTextBuffer *msgstr, *msgid;
1504 gint page_index;
1505 gchar *text;
1506 GtkTextIter start, end;
1507 GtrTabPrivate *priv;
1508
1509 g_return_if_fail (GTR_IS_TAB (tab));
1510
1511 priv = gtr_tab_get_instance_private (tab);
1512
1513 page_index = gtr_tab_get_active_trans_tab (tab);
1514
1515 msgstr =
1516 gtk_text_view_get_buffer (GTK_TEXT_VIEW
1517 (priv->trans_msgstr[page_index]));
1518 msgid = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->text_msgid));
1519
1520 gtk_text_buffer_begin_user_action (msgstr);
1521 gtk_text_buffer_get_bounds (msgid, &start, &end);
1522 text = gtk_text_buffer_get_text (msgid, &start, &end, FALSE);
1523 gtk_text_buffer_set_text (msgstr, text, -1);
1524 g_free (text);
1525 gtk_text_buffer_end_user_action (msgstr);
1526 }
1527
1528 /**
1529 * gtr_tab_block_movement:
1530 * @tab: a #GtrTab
1531 *
1532 * Blocks the movement to the next/prev message.
1533 */
1534 void
gtr_tab_block_movement(GtrTab * tab)1535 gtr_tab_block_movement (GtrTab * tab)
1536 {
1537 GtrTabPrivate *priv;
1538
1539 g_return_if_fail (GTR_IS_TAB (tab));
1540
1541 priv = gtr_tab_get_instance_private (tab);
1542 priv->blocking = TRUE;
1543 }
1544
1545 /**
1546 * gtr_tab_unblock_movement:
1547 * @tab: a #GtrTab
1548 *
1549 * Unblocks the movement to the next/prev message.
1550 */
1551 void
gtr_tab_unblock_movement(GtrTab * tab)1552 gtr_tab_unblock_movement (GtrTab * tab)
1553 {
1554 GtrTabPrivate *priv;
1555
1556 g_return_if_fail (GTR_IS_TAB (tab));
1557
1558 priv = gtr_tab_get_instance_private (tab);
1559 priv->blocking = FALSE;
1560 }
1561
1562 static gboolean
_gtr_tab_finish_edition(GtrTab * tab)1563 _gtr_tab_finish_edition (GtrTab * tab)
1564 {
1565 GList *current_msg;
1566 GtrTabPrivate *priv;
1567
1568 priv = gtr_tab_get_instance_private (tab);
1569
1570 current_msg = gtr_po_get_current_message (priv->po);
1571
1572 /* movement is blocked/unblocked within the handler */
1573 g_signal_emit (G_OBJECT (tab), signals[MESSAGE_EDITION_FINISHED],
1574 0, GTR_MSG (current_msg->data));
1575
1576 return !priv->blocking;
1577 }
1578
1579 /**
1580 * gtr_tab_go_to_next:
1581 * @tab: a #GtrTab
1582 *
1583 * Moves to the next message or plural tab in case the message has plurals.
1584 */
1585 void
gtr_tab_go_to_next(GtrTab * tab)1586 gtr_tab_go_to_next (GtrTab * tab)
1587 {
1588 GtrMsg *msg;
1589 GtrTabPrivate *priv;
1590
1591 priv = gtr_tab_get_instance_private (tab);
1592
1593 if (_gtr_tab_finish_edition (tab))
1594 {
1595 msg = gtr_message_table_navigate (GTR_MESSAGE_TABLE (priv->message_table),
1596 GTR_NAVIGATE_NEXT, NULL);
1597 if (msg)
1598 gtr_tab_message_go_to (tab, msg,
1599 FALSE, GTR_TAB_MOVE_NEXT);
1600 }
1601 }
1602
1603 /**
1604 * gtr_tab_go_to_prev:
1605 * @tab: a #GtrTab
1606 *
1607 * Moves to the previous message or plural tab in case the message has plurals.
1608 */
1609 void
gtr_tab_go_to_prev(GtrTab * tab)1610 gtr_tab_go_to_prev (GtrTab * tab)
1611 {
1612 GtrMsg *msg;
1613 GtrTabPrivate *priv;
1614
1615 priv = gtr_tab_get_instance_private (tab);
1616
1617 if (_gtr_tab_finish_edition (tab))
1618 {
1619 msg = gtr_message_table_navigate (GTR_MESSAGE_TABLE (priv->message_table),
1620 GTR_NAVIGATE_PREV, NULL);
1621 if (msg)
1622 gtr_tab_message_go_to (tab, msg,
1623 FALSE, GTR_TAB_MOVE_PREV);
1624 }
1625 }
1626
1627 /**
1628 * gtr_tab_go_to_first:
1629 * @tab: a #GtrTab
1630 *
1631 * Jumps to the first message.
1632 */
1633 void
gtr_tab_go_to_first(GtrTab * tab)1634 gtr_tab_go_to_first (GtrTab * tab)
1635 {
1636 GtrMsg *msg;
1637 GtrTabPrivate *priv;
1638
1639 priv = gtr_tab_get_instance_private (tab);
1640
1641 if (_gtr_tab_finish_edition (tab))
1642 {
1643 msg = gtr_message_table_navigate (GTR_MESSAGE_TABLE (priv->message_table),
1644 GTR_NAVIGATE_FIRST, NULL);
1645 if (msg)
1646 gtr_tab_message_go_to (tab, msg,
1647 FALSE, GTR_TAB_MOVE_NONE);
1648 }
1649 }
1650
1651 /**
1652 * gtr_tab_go_to_last:
1653 * @tab: a #GtrTab
1654 *
1655 * Jumps to the last message.
1656 */
1657 void
gtr_tab_go_to_last(GtrTab * tab)1658 gtr_tab_go_to_last (GtrTab * tab)
1659 {
1660 GtrMsg *msg;
1661 GtrTabPrivate *priv;
1662
1663 priv = gtr_tab_get_instance_private (tab);
1664
1665 if (_gtr_tab_finish_edition (tab))
1666 {
1667 msg = gtr_message_table_navigate (GTR_MESSAGE_TABLE (priv->message_table),
1668 GTR_NAVIGATE_LAST, NULL);
1669 if (msg)
1670 gtr_tab_message_go_to (tab, msg,
1671 FALSE, GTR_TAB_MOVE_NONE);
1672 }
1673 }
1674
1675 /**
1676 * gtr_tab_go_to_next_fuzzy:
1677 * @tab: a #GtrTab
1678 *
1679 * If there is a next fuzzy message it jumps to it.
1680 *
1681 * Returns: TRUE if there is a next fuzzy message.
1682 */
1683 gboolean
gtr_tab_go_to_next_fuzzy(GtrTab * tab)1684 gtr_tab_go_to_next_fuzzy (GtrTab * tab)
1685 {
1686 GtrMsg *msg;
1687 GtrTabPrivate *priv;
1688
1689 priv = gtr_tab_get_instance_private (tab);
1690
1691 if (!_gtr_tab_finish_edition (tab))
1692 return FALSE;
1693
1694 msg = gtr_message_table_navigate (GTR_MESSAGE_TABLE (priv->message_table),
1695 GTR_NAVIGATE_NEXT,
1696 gtr_msg_is_fuzzy);
1697 if (msg != NULL)
1698 {
1699 gtr_tab_message_go_to (tab, msg, FALSE, GTR_TAB_MOVE_NONE);
1700 return TRUE;
1701 }
1702
1703 return FALSE;
1704 }
1705
1706 /**
1707 * gtr_tab_go_to_prev_fuzzy:
1708 * @tab: a #GtrTab
1709 *
1710 * If there is a prev fuzzy message it jumps to it.
1711 *
1712 * Returns: TRUE if there is a prev fuzzy message.
1713 */
1714 gboolean
gtr_tab_go_to_prev_fuzzy(GtrTab * tab)1715 gtr_tab_go_to_prev_fuzzy (GtrTab * tab)
1716 {
1717 GtrMsg *msg;
1718 GtrTabPrivate *priv;
1719
1720 priv = gtr_tab_get_instance_private (tab);
1721
1722 if (!_gtr_tab_finish_edition (tab))
1723 return FALSE;
1724
1725 msg = gtr_message_table_navigate (GTR_MESSAGE_TABLE (priv->message_table),
1726 GTR_NAVIGATE_PREV,
1727 gtr_msg_is_fuzzy);
1728 if (msg != NULL)
1729 {
1730 gtr_tab_message_go_to (tab, msg, FALSE, GTR_TAB_MOVE_NONE);
1731 return TRUE;
1732 }
1733
1734 return FALSE;
1735 }
1736
1737 static gboolean
message_is_untranslated(GtrMsg * msg)1738 message_is_untranslated (GtrMsg * msg)
1739 {
1740 return !gtr_msg_is_translated (msg);
1741 }
1742
1743 static gboolean
message_is_fuzzy_or_untranslated(GtrMsg * msg)1744 message_is_fuzzy_or_untranslated (GtrMsg * msg)
1745 {
1746 return gtr_msg_is_fuzzy (msg) || !gtr_msg_is_translated (msg);
1747 }
1748
1749 /**
1750 * gtr_tab_go_to_next_untrans:
1751 * @tab: a #GtrTab
1752 *
1753 * If there is a next untranslated message it jumps to it.
1754 *
1755 * Returns: TRUE if there is a next untranslated message.
1756 */
1757 gboolean
gtr_tab_go_to_next_untrans(GtrTab * tab)1758 gtr_tab_go_to_next_untrans (GtrTab * tab)
1759 {
1760 GtrMsg *msg;
1761 GtrTabPrivate *priv;
1762
1763 priv = gtr_tab_get_instance_private (tab);
1764
1765 if (!_gtr_tab_finish_edition (tab))
1766 return FALSE;
1767
1768 msg = gtr_message_table_navigate (GTR_MESSAGE_TABLE (priv->message_table),
1769 GTR_NAVIGATE_NEXT,
1770 message_is_untranslated);
1771 if (msg != NULL)
1772 {
1773 gtr_tab_message_go_to (tab, msg, FALSE, GTR_TAB_MOVE_NONE);
1774 return TRUE;
1775 }
1776
1777 return FALSE;
1778 }
1779
1780 /**
1781 * gtr_tab_go_to_prev_untrans:
1782 * @tab: a #GtrTab
1783 *
1784 * If there is a prev untranslated message it jumps to it.
1785 *
1786 * Returns: TRUE if there is a prev untranslated message.
1787 */
1788 gboolean
gtr_tab_go_to_prev_untrans(GtrTab * tab)1789 gtr_tab_go_to_prev_untrans (GtrTab * tab)
1790 {
1791 GtrMsg *msg;
1792 GtrTabPrivate *priv;
1793
1794 priv = gtr_tab_get_instance_private (tab);
1795
1796 if (!_gtr_tab_finish_edition (tab))
1797 return FALSE;
1798
1799 msg = gtr_message_table_navigate (GTR_MESSAGE_TABLE (priv->message_table),
1800 GTR_NAVIGATE_PREV,
1801 message_is_untranslated);
1802 if (msg != NULL)
1803 {
1804 gtr_tab_message_go_to (tab, msg, FALSE, GTR_TAB_MOVE_NONE);
1805 return TRUE;
1806 }
1807
1808 return FALSE;
1809 }
1810
1811 /**
1812 * gtr_tab_go_to_next_fuzzy_or_untrans:
1813 * @tab: a #GtrTab
1814 *
1815 * If there is a next fuzzy or untranslated message it jumps to it.
1816 *
1817 * Returns: TRUE if there is a next fuzzy or untranslated message.
1818 */
1819 gboolean
gtr_tab_go_to_next_fuzzy_or_untrans(GtrTab * tab)1820 gtr_tab_go_to_next_fuzzy_or_untrans (GtrTab * tab)
1821 {
1822 GtrMsg *msg;
1823 GtrTabPrivate *priv;
1824
1825 priv = gtr_tab_get_instance_private (tab);
1826
1827 if (!_gtr_tab_finish_edition (tab))
1828 return FALSE;
1829
1830 msg = gtr_message_table_navigate (GTR_MESSAGE_TABLE (priv->message_table),
1831 GTR_NAVIGATE_NEXT,
1832 message_is_fuzzy_or_untranslated);
1833 if (msg != NULL)
1834 {
1835 gtr_tab_message_go_to (tab, msg, FALSE, GTR_TAB_MOVE_NONE);
1836 return TRUE;
1837 }
1838
1839 return FALSE;
1840 }
1841
1842 /**
1843 * gtr_tab_go_to_prev_fuzzy_or_untrans:
1844 * @tab: a #GtrTab
1845 *
1846 * If there is a prev fuzzy or untranslated message it jumps to it.
1847 *
1848 * Returns: TRUE if there is a prev fuzzy or untranslated message.
1849 */
1850 gboolean
gtr_tab_go_to_prev_fuzzy_or_untrans(GtrTab * tab)1851 gtr_tab_go_to_prev_fuzzy_or_untrans (GtrTab * tab)
1852 {
1853 GtrMsg *msg;
1854 GtrTabPrivate *priv;
1855
1856 priv = gtr_tab_get_instance_private (tab);
1857
1858 if (!_gtr_tab_finish_edition (tab))
1859 return FALSE;
1860
1861 msg = gtr_message_table_navigate (GTR_MESSAGE_TABLE (priv->message_table),
1862 GTR_NAVIGATE_PREV,
1863 message_is_fuzzy_or_untranslated);
1864 if (msg != NULL)
1865 {
1866 gtr_tab_message_go_to (tab, msg, FALSE, GTR_TAB_MOVE_NONE);
1867 return TRUE;
1868 }
1869
1870 return FALSE;
1871 }
1872
1873 /**
1874 * gtr_tab_go_to_number:
1875 * @tab: a #GtrTab
1876 * @number: the message number you want to jump
1877 *
1878 * Jumps to the message with the @number in the list, if the message does not
1879 * exists it does not jump.
1880 */
1881 void
gtr_tab_go_to_number(GtrTab * tab,gint number)1882 gtr_tab_go_to_number (GtrTab * tab, gint number)
1883 {
1884 GtrPo *po;
1885 GList *msg;
1886
1887 if (!_gtr_tab_finish_edition (tab))
1888 return;
1889
1890 po = gtr_tab_get_po (tab);
1891 msg = gtr_po_get_msg_from_number (po, number);
1892 if (msg != NULL)
1893 {
1894 gtr_tab_message_go_to (tab, msg->data, FALSE, GTR_TAB_MOVE_NONE);
1895 }
1896 }
1897
1898 /**
1899 * gtr_tab_set_info_bar:
1900 * @tab: a #GtrTab
1901 * @infobar: a #GtrMessageArea
1902 *
1903 * Sets the @infobar to be shown in the @tab.
1904 */
1905 void
gtr_tab_set_info_bar(GtrTab * tab,GtkWidget * infobar)1906 gtr_tab_set_info_bar (GtrTab * tab, GtkWidget * infobar)
1907 {
1908 GtrTabPrivate *priv;
1909
1910 g_return_if_fail (GTR_IS_TAB (tab));
1911
1912 priv = gtr_tab_get_instance_private (tab);
1913
1914 if (priv->infobar == infobar)
1915 return;
1916
1917 if (priv->infobar != NULL)
1918 gtk_widget_destroy (priv->infobar);
1919
1920 priv->infobar = infobar;
1921
1922 if (infobar == NULL)
1923 return;
1924
1925 gtk_box_pack_start (GTK_BOX (tab), priv->infobar, FALSE, FALSE, 0);
1926
1927 g_object_add_weak_pointer (G_OBJECT (priv->infobar),
1928 (gpointer *) & priv->infobar);
1929 }
1930
1931 /**
1932 * gtr_tab_set_info:
1933 * @tab: a #GtrTab
1934 * @info: a string to show
1935 *
1936 * Sets the @info to be shown in the @infobar.
1937 */
1938 void
gtr_tab_set_info(GtrTab * tab,const char * primary,const char * secondary)1939 gtr_tab_set_info (GtrTab * tab,
1940 const char * primary,
1941 const char * secondary)
1942 {
1943 GtkWidget *infobar;
1944 infobar = create_info_info_bar (primary, secondary);
1945 gtr_tab_set_info_bar (tab, infobar);
1946 }
1947
1948 GtrMsg *
gtr_tab_get_msg(GtrTab * tab)1949 gtr_tab_get_msg (GtrTab *tab)
1950 {
1951 GtrTabPrivate *priv;
1952 GList *msg_aux;
1953 GtrMsg *msg;
1954
1955 priv = gtr_tab_get_instance_private (tab);
1956 msg_aux = gtr_po_get_current_message (priv->po);
1957 msg = msg_aux->data;
1958
1959 return msg;
1960 }
1961
1962 void
gtr_tab_set_progress(GtrTab * tab,gint trans,gint untrans,gint fuzzy)1963 gtr_tab_set_progress (GtrTab *tab,
1964 gint trans,
1965 gint untrans,
1966 gint fuzzy)
1967 {
1968 GtrTabPrivate *priv = gtr_tab_get_instance_private (tab);
1969 gchar *percentage, *trans_text, *fuzzy_text, *untrans_text;
1970
1971 gtr_progress_set (priv->progress, trans, untrans, fuzzy);
1972
1973 percentage = g_strdup_printf (_("Translated: %0.2f%%"), (float)trans * 100 / (float)(trans + untrans + fuzzy));
1974 trans_text = g_strdup_printf (_("Translated: %d"), trans);
1975 untrans_text = g_strdup_printf (_("Untranslated: %d"), untrans);
1976 fuzzy_text = g_strdup_printf (_("Fuzzy: %d"), fuzzy);
1977
1978 gtk_label_set_text (GTK_LABEL (priv->progress_percentage), percentage);
1979 gtk_label_set_text (GTK_LABEL (priv->progress_fuzzy), fuzzy_text);
1980 gtk_label_set_text (GTK_LABEL (priv->progress_untrans), untrans_text);
1981 gtk_label_set_text (GTK_LABEL (priv->progress_trans), trans_text);
1982
1983 g_free (percentage);
1984 g_free (trans_text);
1985 g_free (fuzzy_text);
1986 g_free (untrans_text);
1987 }
1988
1989 void
gtr_tab_sort_by(GtrTab * tab,GtrMessageTableSortBy sort)1990 gtr_tab_sort_by (GtrTab *tab,
1991 GtrMessageTableSortBy sort)
1992 {
1993 GtrTabPrivate *priv;
1994 priv = gtr_tab_get_instance_private (tab);
1995 gtr_message_table_sort_by (GTR_MESSAGE_TABLE (priv->message_table), sort);
1996 }
1997
1998 void
gtr_tab_find_replace(GtrTab * tab,gboolean set)1999 gtr_tab_find_replace (GtrTab *tab,
2000 gboolean set)
2001 {
2002 GtrTabPrivate *priv;
2003 priv = gtr_tab_get_instance_private (tab);
2004 priv->find_replace_flag = set;
2005 }
2006
2007