GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 <[email protected]> *
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 [email protected] *
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 
38 #define GNC_PREFS_GROUP "dialogs.totd"
39 #define GNC_PREF_CURRENT_TIP "current-tip"
40 #define GNC_PREF_SHOW_TIPS "show-at-startup"
41 #define DIALOG_TOTD_CM_CLASS "dialog-totd"
42 
43 #define GNC_RESPONSE_FORWARD 1
44 #define GNC_RESPONSE_BACK 2
45 
46 /* Callbacks */
47 void gnc_totd_dialog_response_cb (GtkDialog *dialog, gint reponse, gpointer user_data);
48 void gnc_totd_dialog_startup_toggled_cb (GtkToggleButton *button, gpointer user_data);
49 
50 /* The Tips */
51 static gchar **tip_list;
52 static gint tip_count = -1;
53 static gint current_tip_number = -1;
54 
55 /* This static indicates the debugging module that this .o belongs to. */
56 static QofLogModule log_module = GNC_MOD_GUI;
57 
58 typedef struct
59 {
60  GtkWidget *dialog;
61  GtkTextView *textview;
62  GtkWidget *showcheck_button;
63 } TotdDialog;
64 
65 
66 /***********************************************************************
67  * This function should be called to change the tip number. It
68  * handles clamping the number to the range of tips available, saving
69  * the number in the preferences database, and updating the dialog window
70  * with the text of the newly selected tip.
71  *
72  * @param Tip of the day structure. This points to the dialog and
73  * the GtkTextView widget that holds the text of the tip.
74  *
75  * @param offset Which tip to show. If the value is zero then the
76  * current tip will be shown. If the value is negative the previous
77  * tip will be shown. If the value is positive the next tip will be
78  * shown.
79  ************************************************************************/
80 static void
81 gnc_new_tip_number (TotdDialog *totd_dialog, gint offset)
82 {
83 
84  gchar **tip_components = NULL;
85  gchar *tip;
86 
87  ENTER("TotdDialog %p, offset %d", totd_dialog, offset);
88  current_tip_number += offset;
89  DEBUG("clamp %d to '0 <= x < %d'", current_tip_number, tip_count);
90  if (current_tip_number < 0)
91  current_tip_number = tip_count - 1;
92  if (current_tip_number >= tip_count)
93  current_tip_number = 0;
94  gnc_prefs_set_int(GNC_PREFS_GROUP, GNC_PREF_CURRENT_TIP, current_tip_number);
95 
96  /* A tip consists of a translatable string, which might contain a %s
97  * placeholder, optionally followed by a | and a (non-translated)
98  * string to put in the placeholder. For example:
99  *
100  * Welcome to GnuCash version %s|2.4
101  */
102  if (tip_list[current_tip_number])
103  tip_components = g_strsplit(tip_list[current_tip_number], "|", 0);
104  /* If the tip is empty, g_strisplit will return an empty list. This
105  * shouldn't normally happen, but make sure we don't crash just in
106  * case */
107  if (tip_components[0] == NULL)
108  {
109  tip = g_strdup("");
110  }
111  else
112  {
113  /* Use printf to do the substitution. Note that if there is no |
114  * in the tip, tip_components[1] will be the terminating NULL,
115  * so this will never cause an out-of-bounds array access.
116  */
117  tip = g_strdup_printf( _(tip_components[0]), tip_components[1]);
118  }
119 
120  g_strfreev(tip_components);
121  gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(totd_dialog->textview)),
122  tip, -1);
123  g_free(tip);
124  LEAVE("");
125 }
126 
127 
128 /***************************/
129 /* Dialog Callbacks */
130 /***************************/
131 void gnc_totd_dialog_response_cb (GtkDialog *dialog,
132  gint response,
133  gpointer user_data)
134 {
135  TotdDialog *totd_dialog = user_data;
136 
137  ENTER("dialog %p, response %d, user_data %p", dialog, response, user_data);
138  switch (response)
139  {
140  case GNC_RESPONSE_FORWARD:
141  gnc_new_tip_number(totd_dialog, 1);
142  break;
143 
144  case GNC_RESPONSE_BACK:
145  gnc_new_tip_number(totd_dialog, -1);
146  break;
147 
148  case GTK_RESPONSE_CLOSE:
149  gnc_save_window_size(GNC_PREFS_GROUP, GTK_WINDOW(totd_dialog->dialog));
150  /* fall through */
151 
152  default:
153  gnc_unregister_gui_component_by_data(DIALOG_TOTD_CM_CLASS, totd_dialog);
154  gtk_widget_destroy(GTK_WIDGET(totd_dialog->dialog));
155  break;
156  }
157  LEAVE("");
158 }
159 
160 
161 void
162 gnc_totd_dialog_startup_toggled_cb (GtkToggleButton *button,
163  gpointer user_data)
164 {
165  gboolean active;
166 
167  active = gtk_toggle_button_get_active(button);
168  gnc_prefs_set_bool(GNC_PREFS_GROUP, GNC_PREF_SHOW_TIPS, active);
169 }
170 
171 
172 /***********************************/
173 /* Tip of the Day Parser */
174 /***********************************/
175 static gboolean
176 gnc_totd_initialize (void)
177 {
178  gchar *filename, *contents, *new_str;
179  gsize length;
180  GError *error;
181 
182  /* Find the file */
183  filename = gnc_filepath_locate_data_file("tip_of_the_day.list");
184  if (!filename)
185  return FALSE;
186 
187  /* Read it */
188  if (!g_file_get_contents(filename, &contents, &length, &error))
189  {
190  printf("Unable to read file: %s\n", error->message);
191  g_error_free(error);
192  g_free(filename);
193  return FALSE;
194  }
195  g_free(filename);
196 
197  /* Split into multiple strings. Due to the nature of the
198  * tip list file, this can contain empty strings */
199  if (contents)
200  tip_list = g_strsplit(contents, "\n", 0);
201  g_free(contents);
202  contents = NULL;
203 
204  /* Remove the empty strings */
205  for (tip_count = 0; tip_list[tip_count] != NULL; tip_count++)
206  {
207  if (*tip_list[tip_count]!='\0')
208  {
209  g_strstrip(tip_list[tip_count]);
210  if (!contents)
211  contents = g_strdup (tip_list[tip_count]);
212  else
213  {
214  new_str = g_strjoin ("\n", contents, tip_list[tip_count], NULL);
215  g_free (contents);
216  contents = new_str;
217  }
218  }
219  }
220 
221  /* Split cleaned up contents into multiple strings again */
222  g_strfreev (tip_list);
223  if (contents)
224  tip_list = g_strsplit(contents, "\n", 0);
225 
226  /* Convert any escaped characters while counting the strings */
227  for (tip_count = 0; tip_list[tip_count] != NULL; tip_count++)
228  {
229  new_str = g_strcompress(tip_list[tip_count]);
230  g_free(tip_list[tip_count]);
231  tip_list[tip_count] = new_str;
232  }
233 
234 
235  /* Don't continue when no tips were found, to prevent
236  * gnc_new_tip_number doesn't handle that case (it would try to
237  * display the terminating NULL). There's nothing to show
238  * anyway...*/
239  if (tip_count == 0)
240  {
241  PWARN("No tips found - Tips of the day window won't be displayed.");
242  return FALSE;
243  }
244 
245  return TRUE;
246 }
247 
248 
249 /***********************************************************************
250  * Raise the totd dialog to the top of the window stack. This
251  * function is called if the user attempts to create a second totd
252  * dialog.
253  *
254  * @internal
255  *
256  * @param class_name Unused.
257  *
258  * @param component_id Unused.
259  *
260  * @param user_data A pointer to the totd structure.
261  *
262  * @param iter_data Unused.
263  ***********************************************************************/
264 static gboolean
265 show_handler (const char *class_name, gint component_id,
266  gpointer user_data, gpointer iter_data)
267 {
268  TotdDialog *totd_dialog = user_data;
269 
270  ENTER(" ");
271  if (!totd_dialog)
272  {
273  LEAVE("no data strucure");
274  return(FALSE);
275  }
276 
277  gtk_window_present(GTK_WINDOW(totd_dialog->dialog));
278  LEAVE(" ");
279  return(TRUE);
280 }
281 
282 
283 /****************************************************
284  * Close the totd dialog.
285  *
286  * @internal
287  *
288  * @param user_data A pointer to the totd structure.
289  ****************************************************/
290 static void
291 close_handler (gpointer user_data)
292 {
293  TotdDialog *totd_dialog = user_data;
294 
295  ENTER(" ");
296 
297  gnc_unregister_gui_component_by_data(DIALOG_TOTD_CM_CLASS, totd_dialog);
298 
299  LEAVE(" ");
300 }
301 
302 
303 /*************************************/
304 /* Create the TotD Dialog */
305 /*************************************/
306 void
307 gnc_totd_dialog (GtkWindow *parent, gboolean startup)
308 {
309  TotdDialog *totd_dialog;
310 
311  GtkBuilder *builder;
312  GtkWidget *dialog, *button;
313  GtkTextView *textview;
314  gboolean show_tips;
315 
316  totd_dialog = g_new0 (TotdDialog, 1);
317 
318  show_tips = gnc_prefs_get_bool(GNC_PREFS_GROUP, GNC_PREF_SHOW_TIPS);
319  if (startup && !show_tips)
320  return;
321 
322  if (tip_count == -1)
323  {
324  if (!gnc_totd_initialize())
325  return;
326  current_tip_number = gnc_prefs_get_int(GNC_PREFS_GROUP, GNC_PREF_CURRENT_TIP);
327  }
328 
329  if (gnc_forall_gui_components(DIALOG_TOTD_CM_CLASS, show_handler, NULL))
330  {
331  return;
332  }
333 
334  builder = gtk_builder_new();
335  gnc_builder_add_from_file (builder, "dialog-totd.glade", "totd_dialog");
336  dialog = GTK_WIDGET(gtk_builder_get_object (builder, "totd_dialog"));
337  gtk_window_set_transient_for(GTK_WINDOW (dialog), parent);
338 
339  totd_dialog->dialog = dialog;
340 
341  ENTER("totd_dialog %p, dialog %p", totd_dialog, dialog);
342 
343  gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, totd_dialog);
344 
345  button = GTK_WIDGET(gtk_builder_get_object (builder, "show_checkbutton"));
346  totd_dialog->showcheck_button = button;
347 
348  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (button), show_tips);
349 
350  textview = GTK_TEXT_VIEW(gtk_builder_get_object (builder, "tip_textview"));
351  totd_dialog->textview = textview;
352 
353  gnc_new_tip_number(totd_dialog, 1);
354 
355  gnc_restore_window_size(GNC_PREFS_GROUP, GTK_WINDOW(totd_dialog->dialog));
356  gtk_widget_show(GTK_WIDGET (totd_dialog->dialog));
357 
358  gnc_register_gui_component(DIALOG_TOTD_CM_CLASS,
359  NULL, close_handler, totd_dialog);
360 
361  g_object_unref(G_OBJECT(builder));
362 
363  LEAVE("");
364 }
gchar * gnc_filepath_locate_data_file(const gchar *name)
#define DEBUG(format, args...)
Definition: qoflog.h:255
gboolean gnc_prefs_set_int(const gchar *group, const gchar *pref_name, gint value)
Definition: gnc-prefs.c:293
#define ENTER(format, args...)
Definition: qoflog.h:261
gint gnc_prefs_get_int(const gchar *group, const gchar *pref_name)
Definition: gnc-prefs.c:206
#define PWARN(format, args...)
Definition: qoflog.h:243
gboolean gnc_prefs_set_bool(const gchar *group, const gchar *pref_name, gboolean value)
Definition: gnc-prefs.c:282
Gnome specific utility functions.
All type declarations for the whole Gnucash engine.
Generic api to store and retrieve preferences.
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Definition: gnc-prefs.c:196
#define LEAVE(format, args...)
Definition: qoflog.h:271
File path resolution utility functions.
const gchar * QofLogModule
Definition: qofid.h:89