GnuCash c935c2f+
Loading...
Searching...
No Matches
dialog-totd.c
1/********************************************************************\
2 * dialog-totd.c : dialog to display a "tip of the day" *
3 * *
4 * Initial copyright not recorded. *
5 * Copyright (c) 2006 David Hampton <hampton@employees.org> *
6 * Copyright (c) 2011 Robert Fewell *
7 * *
8 * This program is free software; you can redistribute it and/or *
9 * modify it under the terms of the GNU General Public License as *
10 * published by the Free Software Foundation; either version 2 of *
11 * the License, or (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License*
19 * along with this program; if not, contact: *
20 * *
21 * Free Software Foundation Voice: +1-617-542-5942 *
22 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
23 * Boston, MA 02110-1301, USA gnu@gnu.org *
24\********************************************************************/
25
26#include <config.h>
27#include <gtk/gtk.h>
28#include <glib/gi18n.h>
29
30#include "dialog-totd.h"
31#include "dialog-utils.h"
32#include "gnc-component-manager.h"
33#include "gnc-filepath-utils.h"
34#include "gnc-prefs.h"
35#include "gnc-gnome-utils.h"
36#include "gnc-engine.h"
37#include "gnc-ui.h"
38
39#define GNC_PREFS_GROUP "dialogs.totd"
40#define GNC_PREF_CURRENT_TIP "current-tip"
41#define GNC_PREF_SHOW_TIPS "show-at-startup"
42#define DIALOG_TOTD_CM_CLASS "dialog-totd"
43
44#define GNC_RESPONSE_FORWARD 1
45#define GNC_RESPONSE_BACK 2
46
47/* Callbacks */
48void gnc_totd_dialog_response_cb (GtkDialog *dialog, gint response, gpointer user_data);
49void gnc_totd_dialog_startup_toggled_cb (GtkToggleButton *button, gpointer user_data);
50
51/* The Tips */
52static gchar **tip_list;
53static gint tip_count = -1;
54static gint current_tip_number = -1;
55
56/* This static indicates the debugging module that this .o belongs to. */
57static QofLogModule log_module = GNC_MOD_GUI;
58
59typedef struct
60{
61 GtkWidget *dialog;
62 GtkTextView *textview;
63 GtkWidget *showcheck_button;
65
66
67/***********************************************************************
68 * This function should be called to change the tip number. It
69 * handles clamping the number to the range of tips available, saving
70 * the number in the preferences database, and updating the dialog window
71 * with the text of the newly selected tip.
72 *
73 * @param Tip of the day structure. This points to the dialog and
74 * the GtkTextView widget that holds the text of the tip.
75 *
76 * @param offset Which tip to show. If the value is zero then the
77 * current tip will be shown. If the value is negative the previous
78 * tip will be shown. If the value is positive the next tip will be
79 * shown.
80 ************************************************************************/
81static void
82gnc_new_tip_number (TotdDialog *totd_dialog, gint offset)
83{
84
85 gchar **tip_components = NULL;
86 gchar *tip;
87
88 ENTER("TotdDialog %p, offset %d", totd_dialog, offset);
89 g_return_if_fail (tip_list != NULL);
90 current_tip_number += offset;
91 DEBUG("clamp %d to '0 <= x < %d'", current_tip_number, tip_count);
92 if (current_tip_number < 0)
93 current_tip_number = tip_count - 1;
94 if (current_tip_number >= tip_count)
95 current_tip_number = 0;
96 gnc_prefs_set_int(GNC_PREFS_GROUP, GNC_PREF_CURRENT_TIP, current_tip_number);
97
98 /* A tip consists of a translatable string, which might contain a %s
99 * placeholder, optionally followed by a | and a (non-translated)
100 * string to put in the placeholder. For example:
101 *
102 * Welcome to GnuCash version %s|2.4
103 */
104 if (tip_list[current_tip_number])
105 tip_components = g_strsplit(tip_list[current_tip_number], "|", 0);
106 /* If the tip is empty, g_strsplit will return an empty list. This
107 * shouldn't normally happen, but make sure we don't crash just in
108 * case */
109 if (tip_components == NULL)
110 {
111 tip = g_strdup("");
112 }
113 else
114 {
115 /* Use printf to do the substitution. Note that if there is no |
116 * in the tip, tip_components[1] will be the terminating NULL,
117 * so this will never cause an out-of-bounds array access.
118 */
119 tip = g_strdup_printf( _(tip_components[0]), tip_components[1]);
120 }
121
122 g_strfreev(tip_components);
123 gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(totd_dialog->textview)),
124 tip, -1);
125 g_free(tip);
126 LEAVE("");
127}
128
129
130/***************************/
131/* Dialog Callbacks */
132/***************************/
133void gnc_totd_dialog_response_cb (GtkDialog *dialog,
134 gint response,
135 gpointer user_data)
136{
137 TotdDialog *totd_dialog = user_data;
138
139 ENTER("dialog %p, response %d, user_data %p", dialog, response, user_data);
140 switch (response)
141 {
142 case GNC_RESPONSE_FORWARD:
143 gnc_new_tip_number(totd_dialog, 1);
144 break;
145
146 case GNC_RESPONSE_BACK:
147 gnc_new_tip_number(totd_dialog, -1);
148 break;
149
150 case GTK_RESPONSE_CLOSE:
151 gnc_save_window_size(GNC_PREFS_GROUP, GTK_WINDOW(totd_dialog->dialog));
152 /* fall through */
153
154 default:
155 gnc_unregister_gui_component_by_data(DIALOG_TOTD_CM_CLASS, totd_dialog);
156 gtk_widget_destroy(GTK_WIDGET(totd_dialog->dialog));
157 break;
158 }
159 LEAVE("");
160}
161
162
163void
164gnc_totd_dialog_startup_toggled_cb (GtkToggleButton *button,
165 gpointer user_data)
166{
167 gboolean active;
168
169 active = gtk_toggle_button_get_active(button);
170 gnc_prefs_set_bool(GNC_PREFS_GROUP, GNC_PREF_SHOW_TIPS, active);
171}
172
173
174/***********************************/
175/* Tip of the Day Parser */
176/***********************************/
177static gboolean
178gnc_totd_initialize (void)
179{
180 gchar *filename = NULL, *contents = NULL, *new_str = NULL;
181 gsize length;
182 GError *error = NULL;
183 int tip;
184
185 /* Find the file */
186 filename = gnc_filepath_locate_data_file("tip_of_the_day.list");
187 if (!filename)
188 return FALSE;
189
190 /* Read it */
191 if (!g_file_get_contents(filename, &contents, &length, &error))
192 {
193 printf("Unable to read file: %s\n", error->message);
194 g_error_free(error);
195 g_free(filename);
196 return FALSE;
197 }
198 g_free(filename);
199
200 /* Split into multiple strings. Due to the nature of the
201 * tip list file, this can contain empty strings */
202 if (contents)
203 {
204 tip_list = g_strsplit(contents, "\n", 0);
205 g_free(contents);
206 contents = NULL;
207 }
208
209 tip_count = g_strv_length (tip_list);
210
211 /* Remove the empty strings */
212 for (tip = 0; tip < tip_count; ++tip)
213 {
214 if (*tip_list[tip] != '\0')
215 {
216 g_strstrip(tip_list[tip]);
217 if (!contents)
218 contents = g_strdup (tip_list[tip]);
219 else
220 {
221 new_str = g_strjoin ("\n", contents, tip_list[tip], NULL);
222 g_free (contents);
223 contents = new_str;
224 }
225 }
226 }
227
228 /* Split cleaned up contents into multiple strings again */
229 g_strfreev (tip_list);
230 tip_list = NULL;
231 if (contents)
232 {
233 tip_list = g_strsplit(contents, "\n", 0);
234 tip_count = g_strv_length (tip_list);
235
236 /* Convert any escaped characters while counting the strings */
237 for (tip = 0; tip < tip_count; ++tip)
238 {
239 new_str = g_strcompress(tip_list[tip]);
240 g_free(tip_list[tip]);
241 tip_list[tip] = new_str;
242 }
243 g_free (contents);
244 }
245 if (tip_count < 1)
246 return FALSE;
247 return TRUE;
248}
249
250
251/***********************************************************************
252 * Raise the totd dialog to the top of the window stack. This
253 * function is called if the user attempts to create a second totd
254 * dialog.
255 *
256 * @internal
257 *
258 * @param class_name Unused.
259 *
260 * @param component_id Unused.
261 *
262 * @param user_data A pointer to the totd structure.
263 *
264 * @param iter_data Unused.
265 ***********************************************************************/
266static gboolean
267show_handler (const char *class_name, gint component_id,
268 gpointer user_data, gpointer iter_data)
269{
270 TotdDialog *totd_dialog = user_data;
271
272 ENTER(" ");
273 if (!totd_dialog)
274 {
275 LEAVE("no data structure");
276 return(FALSE);
277 }
278
279 gtk_window_set_transient_for (GTK_WINDOW (totd_dialog->dialog),
281 LEAVE(" ");
282 return(TRUE);
283}
284
285
286/****************************************************
287 * Close the totd dialog.
288 *
289 * @internal
290 *
291 * @param user_data A pointer to the totd structure.
292 ****************************************************/
293static void
294close_handler (gpointer user_data)
295{
296 TotdDialog *totd_dialog = user_data;
297
298 ENTER(" ");
299
300 gnc_unregister_gui_component_by_data(DIALOG_TOTD_CM_CLASS, totd_dialog);
301
302 LEAVE(" ");
303}
304
305
306/*************************************/
307/* Create the TotD Dialog */
308/*************************************/
309void
310gnc_totd_dialog (GtkWindow *parent, gboolean startup)
311{
312 TotdDialog *totd_dialog;
313
314 GtkBuilder *builder;
315 GtkWidget *dialog, *button;
316 GtkTextView *textview;
317 gboolean show_tips;
318
319 show_tips = gnc_prefs_get_bool(GNC_PREFS_GROUP, GNC_PREF_SHOW_TIPS);
320 if (startup && !show_tips)
321 return;
322
323 if (tip_count == -1)
324 {
325 if (!gnc_totd_initialize())
326 return;
327 current_tip_number = gnc_prefs_get_int(GNC_PREFS_GROUP, GNC_PREF_CURRENT_TIP);
328 }
329
330 /* Don't continue when no tips were found, to prevent
331 * gnc_new_tip_number doesn't handle that case (it would try to
332 * display the terminating NULL). There's nothing to show
333 * anyway...*/
334 if (tip_count < 1)
335 {
336 PWARN("No tips found - Tips of the day window won't be displayed.");
337 return;
338 }
339 if (gnc_forall_gui_components(DIALOG_TOTD_CM_CLASS, show_handler, NULL))
340 {
341 return;
342 }
343
344 builder = gtk_builder_new();
345 gnc_builder_add_from_file (builder, "dialog-totd.glade", "totd_dialog");
346 dialog = GTK_WIDGET(gtk_builder_get_object (builder, "totd_dialog"));
347 gtk_window_set_transient_for(GTK_WINDOW (dialog), parent);
348
349 // Set the name for this dialog so it can be easily manipulated with css
350 gtk_widget_set_name (GTK_WIDGET(dialog), "gnc-id-tip-of-the-day");
351
352 totd_dialog = g_new0 (TotdDialog, 1);
353 totd_dialog->dialog = dialog;
354
355 ENTER("totd_dialog %p, dialog %p", totd_dialog, dialog);
356
357 gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, totd_dialog);
358
359 button = GTK_WIDGET(gtk_builder_get_object (builder, "show_checkbutton"));
360 totd_dialog->showcheck_button = button;
361
362 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (button), show_tips);
363
364 textview = GTK_TEXT_VIEW(gtk_builder_get_object (builder, "tip_textview"));
365 totd_dialog->textview = textview;
366
367 gnc_new_tip_number(totd_dialog, 1);
368
369 gnc_restore_window_size(GNC_PREFS_GROUP, GTK_WINDOW(totd_dialog->dialog), parent);
370 gtk_widget_show(GTK_WIDGET (totd_dialog->dialog));
371
372 gnc_register_gui_component(DIALOG_TOTD_CM_CLASS,
373 NULL, close_handler, totd_dialog);
374
375 g_object_unref(G_OBJECT(builder));
376
377 LEAVE("");
378}
379
380
381
382/****************************************************
383 * Set the totd dialog transient for the currently
384 * active main window. This will prevent the totd
385 * dialog from accidentally hiding behind a main
386 * window.
387 ****************************************************/
388void
389gnc_totd_dialog_reparent (void)
390{
391 gnc_forall_gui_components(DIALOG_TOTD_CM_CLASS, show_handler, NULL);
392}
All type declarations for the whole Gnucash engine.
File path resolution utility functions.
Gnome specific utility functions.
Generic api to store and retrieve preferences.
GtkWindow * gnc_ui_get_main_window(GtkWidget *widget)
Get a pointer to the final GncMainWindow widget is rooted in.
#define DEBUG(format, args...)
Print a debugging message.
Definition qoflog.h:264
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition qoflog.h:282
#define PWARN(format, args...)
Log a warning.
Definition qoflog.h:250
#define ENTER(format, args...)
Print a function entry debugging message.
Definition qoflog.h:272
gboolean gnc_prefs_set_bool(const gchar *group, const gchar *pref_name, gboolean value)
Store a boolean value into the preferences backend.
gint gnc_prefs_get_int(const gchar *group, const gchar *pref_name)
Get an integer value from the preferences backend.
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
gboolean gnc_prefs_set_int(const gchar *group, const gchar *pref_name, gint value)
Store an integer value into the preferences backend.