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