1 /*
2  * xed-statusbar.c
3  * This file is part of xed
4  *
5  * Copyright (C) 2005 - Paolo Borelli
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 /*
24  * Modified by the xed Team, 2005. See the AUTHORS file for a
25  * list of people on the xed Team.
26  * See the ChangeLog files for a list of changes.
27  *
28  * $Id$
29  */
30 
31 #include <config.h>
32 #include <string.h>
33 #include <glib/gi18n.h>
34 #include <gtk/gtk.h>
35 
36 #include "xed-statusbar.h"
37 
38 struct _XedStatusbarPrivate
39 {
40     GtkWidget *overwrite_mode_label;
41     GtkWidget *cursor_position_label;
42 
43     GtkWidget *state_frame;
44     GtkWidget *load_image;
45     GtkWidget *save_image;
46     GtkWidget *print_image;
47 
48     GtkWidget *error_frame;
49     GtkWidget *error_event_box;
50 
51     /* tmp flash timeout data */
52     guint flash_timeout;
53     guint flash_context_id;
54     guint flash_message_id;
55 };
56 
G_DEFINE_TYPE_WITH_PRIVATE(XedStatusbar,xed_statusbar,GTK_TYPE_STATUSBAR)57 G_DEFINE_TYPE_WITH_PRIVATE (XedStatusbar, xed_statusbar, GTK_TYPE_STATUSBAR)
58 
59 
60 static gchar *
61 get_overwrite_mode_string (gboolean overwrite)
62 {
63     return g_strconcat ("  ", overwrite ? _("OVR") :  _("INS"), NULL);
64 }
65 
66 static gint
get_overwrite_mode_length(void)67 get_overwrite_mode_length (void)
68 {
69     return 2 + MAX (g_utf8_strlen (_("OVR"), -1), g_utf8_strlen (_("INS"), -1));
70 }
71 
72 static void
xed_statusbar_dispose(GObject * object)73 xed_statusbar_dispose (GObject *object)
74 {
75     XedStatusbar *statusbar = XED_STATUSBAR (object);
76 
77     if (statusbar->priv->flash_timeout > 0)
78     {
79         g_source_remove (statusbar->priv->flash_timeout);
80         statusbar->priv->flash_timeout = 0;
81     }
82 
83     G_OBJECT_CLASS (xed_statusbar_parent_class)->dispose (object);
84 }
85 
86 static void
xed_statusbar_class_init(XedStatusbarClass * klass)87 xed_statusbar_class_init (XedStatusbarClass *klass)
88 {
89     GObjectClass *object_class = G_OBJECT_CLASS (klass);
90 
91     object_class->dispose = xed_statusbar_dispose;
92 }
93 
94 #define CURSOR_POSITION_LABEL_WIDTH_CHARS 18
95 
96 static void
xed_statusbar_init(XedStatusbar * statusbar)97 xed_statusbar_init (XedStatusbar *statusbar)
98 {
99     GtkWidget *hbox;
100     GtkWidget *error_image;
101 
102     statusbar->priv = xed_statusbar_get_instance_private (statusbar);
103 
104     gtk_widget_set_margin_top (GTK_WIDGET (statusbar), 0);
105     gtk_widget_set_margin_bottom (GTK_WIDGET (statusbar), 0);
106 
107     statusbar->priv->overwrite_mode_label = gtk_label_new (NULL);
108     gtk_label_set_width_chars (GTK_LABEL (statusbar->priv->overwrite_mode_label), get_overwrite_mode_length ());
109     gtk_widget_show (statusbar->priv->overwrite_mode_label);
110     gtk_box_pack_end (GTK_BOX (statusbar), statusbar->priv->overwrite_mode_label, FALSE, TRUE, 0);
111     gtk_widget_set_margin_end (GTK_WIDGET (statusbar->priv->overwrite_mode_label), 6);
112 
113     statusbar->priv->cursor_position_label = gtk_label_new (NULL);
114     gtk_label_set_width_chars (GTK_LABEL (statusbar->priv->cursor_position_label), CURSOR_POSITION_LABEL_WIDTH_CHARS);
115     gtk_widget_show (statusbar->priv->cursor_position_label);
116     gtk_box_pack_end (GTK_BOX (statusbar), statusbar->priv->cursor_position_label, FALSE, TRUE, 0);
117 
118     statusbar->priv->state_frame = gtk_frame_new (NULL);
119     gtk_frame_set_shadow_type (GTK_FRAME (statusbar->priv->state_frame), GTK_SHADOW_IN);
120 
121     hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
122     gtk_container_add (GTK_CONTAINER (statusbar->priv->state_frame), hbox);
123 
124     statusbar->priv->load_image = gtk_image_new_from_icon_name ("document-open-symbolic", GTK_ICON_SIZE_MENU);
125     statusbar->priv->save_image = gtk_image_new_from_icon_name ("document-save-symbolic", GTK_ICON_SIZE_MENU);
126     statusbar->priv->print_image = gtk_image_new_from_icon_name ("printer-symbolic", GTK_ICON_SIZE_MENU);
127 
128     gtk_widget_show (hbox);
129 
130     gtk_box_pack_start (GTK_BOX (hbox), statusbar->priv->load_image, FALSE, TRUE, 4);
131     gtk_box_pack_start (GTK_BOX (hbox), statusbar->priv->save_image, FALSE, TRUE, 4);
132     gtk_box_pack_start (GTK_BOX (hbox), statusbar->priv->print_image, FALSE, TRUE, 4);
133 
134     gtk_box_pack_start (GTK_BOX (statusbar), statusbar->priv->state_frame, FALSE, TRUE, 0);
135 
136     statusbar->priv->error_frame = gtk_frame_new (NULL);
137     gtk_frame_set_shadow_type (GTK_FRAME (statusbar->priv->error_frame), GTK_SHADOW_IN);
138 
139     error_image = gtk_image_new_from_icon_name ("dialog-error", GTK_ICON_SIZE_MENU);
140 
141     gtk_widget_set_margin_start (error_image, 4);
142     gtk_widget_set_margin_end (error_image, 4);
143     gtk_widget_set_margin_top (error_image, 0);
144     gtk_widget_set_margin_bottom (error_image, 0);
145 
146     statusbar->priv->error_event_box = gtk_event_box_new ();
147     gtk_event_box_set_visible_window  (GTK_EVENT_BOX (statusbar->priv->error_event_box), FALSE);
148     gtk_widget_show (statusbar->priv->error_event_box);
149 
150     gtk_container_add (GTK_CONTAINER (statusbar->priv->error_frame), statusbar->priv->error_event_box);
151     gtk_container_add (GTK_CONTAINER (statusbar->priv->error_event_box), error_image);
152 
153     gtk_box_pack_start (GTK_BOX (statusbar), statusbar->priv->error_frame, FALSE, TRUE, 0);
154 
155     gtk_style_context_add_class (gtk_widget_get_style_context GTK_WIDGET (statusbar), "xed-statusbar");
156 }
157 
158 /**
159  * xed_statusbar_new:
160  *
161  * Creates a new #XedStatusbar.
162  *
163  * Return value: the new #XedStatusbar object
164  **/
165 GtkWidget *
xed_statusbar_new(void)166 xed_statusbar_new (void)
167 {
168     return GTK_WIDGET (g_object_new (XED_TYPE_STATUSBAR, NULL));
169 }
170 
171 /**
172  * xed_statusbar_set_overwrite:
173  * @statusbar: a #XedStatusbar
174  * @overwrite: if the overwrite mode is set
175  *
176  * Sets the overwrite mode on the statusbar.
177  **/
178 void
xed_statusbar_set_overwrite(XedStatusbar * statusbar,gboolean overwrite)179 xed_statusbar_set_overwrite (XedStatusbar *statusbar,
180                              gboolean      overwrite)
181 {
182     gchar *msg;
183 
184     g_return_if_fail (XED_IS_STATUSBAR (statusbar));
185 
186     msg = get_overwrite_mode_string (overwrite);
187 
188     gtk_label_set_text (GTK_LABEL (statusbar->priv->overwrite_mode_label), msg);
189 
190     g_free (msg);
191 }
192 
193 void
xed_statusbar_clear_overwrite(XedStatusbar * statusbar)194 xed_statusbar_clear_overwrite (XedStatusbar *statusbar)
195 {
196     g_return_if_fail (XED_IS_STATUSBAR (statusbar));
197 
198     gtk_label_set_text (GTK_LABEL (statusbar->priv->overwrite_mode_label), NULL);
199 }
200 
201 /**
202  * xed_statusbar_cursor_position:
203  * @statusbar: an #XedStatusbar
204  * @line: line position
205  * @col: column position
206  *
207  * Sets the cursor position on the statusbar.
208  **/
209 void
xed_statusbar_set_cursor_position(XedStatusbar * statusbar,gint line,gint col)210 xed_statusbar_set_cursor_position (XedStatusbar *statusbar,
211                                    gint          line,
212                                    gint          col)
213 {
214     gchar *msg = NULL;
215 
216     g_return_if_fail (XED_IS_STATUSBAR (statusbar));
217 
218     if ((line >= 0) || (col >= 0))
219     {
220         /* Translators: "Ln" is an abbreviation for "Line", Col is an abbreviation for "Column". Please,
221         use abbreviations if possible to avoid space problems. */
222         msg = g_strdup_printf (_("  Ln %d, Col %d"), line, col);
223     }
224 
225     gtk_label_set_text (GTK_LABEL (statusbar->priv->cursor_position_label), msg);
226 
227     g_free (msg);
228 }
229 
230 static gboolean
remove_message_timeout(XedStatusbar * statusbar)231 remove_message_timeout (XedStatusbar *statusbar)
232 {
233     gtk_statusbar_remove (GTK_STATUSBAR (statusbar),
234                           statusbar->priv->flash_context_id,
235                           statusbar->priv->flash_message_id);
236 
237     /* remove the timeout */
238     statusbar->priv->flash_timeout = 0;
239     return FALSE;
240 }
241 
242 /* FIXME this is an issue for introspection */
243 /**
244  * xed_statusbar_flash_message:
245  * @statusbar: a #XedStatusbar
246  * @context_id: message context_id
247  * @format: message to flash on the statusbar
248  * @...: format arguments
249  *
250  * Flash a temporary message on the statusbar.
251  */
252 void
xed_statusbar_flash_message(XedStatusbar * statusbar,guint context_id,const gchar * format,...)253 xed_statusbar_flash_message (XedStatusbar *statusbar,
254                              guint         context_id,
255                              const gchar  *format, ...)
256 {
257     const guint32 flash_length = 3000; /* three seconds */
258     va_list args;
259     gchar *msg;
260 
261     g_return_if_fail (XED_IS_STATUSBAR (statusbar));
262     g_return_if_fail (format != NULL);
263 
264     va_start (args, format);
265     msg = g_strdup_vprintf (format, args);
266     va_end (args);
267 
268     /* remove a currently ongoing flash message */
269     if (statusbar->priv->flash_timeout > 0)
270     {
271         g_source_remove (statusbar->priv->flash_timeout);
272         statusbar->priv->flash_timeout = 0;
273 
274         gtk_statusbar_remove (GTK_STATUSBAR (statusbar),
275                               statusbar->priv->flash_context_id,
276                               statusbar->priv->flash_message_id);
277     }
278 
279     statusbar->priv->flash_context_id = context_id;
280     statusbar->priv->flash_message_id = gtk_statusbar_push (GTK_STATUSBAR (statusbar), context_id, msg);
281 
282     statusbar->priv->flash_timeout = g_timeout_add (flash_length,
283                                                     (GSourceFunc) remove_message_timeout,
284                                                     statusbar);
285 
286     g_free (msg);
287 }
288 
289 void
xed_statusbar_set_window_state(XedStatusbar * statusbar,XedWindowState state,gint num_of_errors)290 xed_statusbar_set_window_state (XedStatusbar   *statusbar,
291                                 XedWindowState  state,
292                                 gint            num_of_errors)
293 {
294     g_return_if_fail (XED_IS_STATUSBAR (statusbar));
295 
296     gtk_widget_hide (statusbar->priv->state_frame);
297     gtk_widget_hide (statusbar->priv->save_image);
298     gtk_widget_hide (statusbar->priv->load_image);
299     gtk_widget_hide (statusbar->priv->print_image);
300 
301     if (state & XED_WINDOW_STATE_SAVING)
302     {
303         gtk_widget_show (statusbar->priv->state_frame);
304         gtk_widget_show (statusbar->priv->save_image);
305     }
306     if (state & XED_WINDOW_STATE_LOADING)
307     {
308         gtk_widget_show (statusbar->priv->state_frame);
309         gtk_widget_show (statusbar->priv->load_image);
310     }
311 
312     if (state & XED_WINDOW_STATE_PRINTING)
313     {
314         gtk_widget_show (statusbar->priv->state_frame);
315         gtk_widget_show (statusbar->priv->print_image);
316     }
317 
318     if (state & XED_WINDOW_STATE_ERROR)
319     {
320         gchar *tip;
321 
322         tip = g_strdup_printf (ngettext("There is a tab with errors",
323                                "There are %d tabs with errors",
324                                num_of_errors),
325                                num_of_errors);
326 
327         gtk_widget_set_tooltip_text (statusbar->priv->error_event_box, tip);
328         g_free (tip);
329 
330         gtk_widget_show (statusbar->priv->error_frame);
331     }
332     else
333     {
334         gtk_widget_hide (statusbar->priv->error_frame);
335     }
336 }
337 
338 
339