GnuCash c935c2f+
Loading...
Searching...
No Matches
dialog-dup-trans.c
1/********************************************************************\
2 * dialog-dup-trans.c -- duplicate transaction dialog *
3 * Copyright (C) 2001 Gnumatic, Inc. *
4 * Author: Dave Peticolas <dave@krondo.com> *
5 * *
6 * This program is free software; you can redistribute it and/or *
7 * modify it under the terms of the GNU General Public License as *
8 * published by the Free Software Foundation; either version 2 of *
9 * the License, or (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License*
17 * along with this program; if not, contact: *
18 * *
19 * Free Software Foundation Voice: +1-617-542-5942 *
20 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21 * Boston, MA 02110-1301, USA gnu@gnu.org *
22\********************************************************************/
23
24#include <config.h>
25
26#include <gtk/gtk.h>
27#include <glib/gi18n.h>
28#include <time.h>
29#include <stdlib.h>
30
31#include "dialog-dup-trans.h"
32#include "dialog-utils.h"
33#include "gnc-date-edit.h"
34#include "qof.h"
35
36/* This static indicates the debugging module that this .o belongs to. */
37G_GNUC_UNUSED static QofLogModule log_module = G_LOG_DOMAIN;
38
39typedef struct
40{
41 GtkWidget * dialog;
42
43 gboolean focus_out;
44
45 GtkWidget * date_edit;
46 GtkWidget * num_edit;
47 GtkWidget * tnum_edit;
48 GtkWidget * link_edit;
49
50 GtkWidget *duplicate_title_label; // GtkLabel
51 GtkWidget *duplicate_table; // GtkTable
52 GtkWidget *date_label; // GtkLabel
53 GtkWidget *num_label; // GtkLabel
54 GtkWidget *tnum_label; // GtkLabel
55 GtkWidget *link_label; // GtkLabel
57
58/* Parses the string value and returns true if it is a
59 * number. In that case, *num is set to the value parsed.
60 * Copied from numcell.c */
61static gboolean
62parse_num (const char *string, long int *num)
63{
64 long int number;
65
66 if (string == NULL)
67 return FALSE;
68
69 if (!gnc_strisnum (string))
70 return FALSE;
71
72 number = strtol (string, NULL, 10);
73
74 if ((number == LONG_MIN) || (number == LONG_MAX))
75 return FALSE;
76
77 if (num != NULL)
78 *num = number;
79
80 return TRUE;
81}
82
83static gboolean
84gnc_dup_inc_dec (GtkWidget *widget, const gchar *text, gint inc_dec)
85{
86 long int num;
87
88 if (parse_num (text, &num))
89 {
90 gchar *format;
91 gchar *out;
92 num = num + inc_dec;
93
94 if (num == -1)
95 num = 0;
96
97 if (g_str_has_prefix (text, "0"))
98 format = g_strdup_printf ("%s%ld%s", "%0", g_utf8_strlen (text, -1), "d");
99 else
100 format = g_strdup_printf ("%s", "%ld");
101
102 out = g_strdup_printf (format, num);
103
104 gtk_entry_set_text (GTK_ENTRY(widget), out);
105 g_free (format);
106 g_free (out);
107 return TRUE;
108 }
109 return FALSE;
110}
111
112static gboolean
113gnc_dup_key_press_event_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
114{
115 const gchar *text = gtk_entry_get_text (GTK_ENTRY(widget));
116
117 if (gnc_strisnum (text))
118 {
119 GdkModifierType modifiers = gtk_accelerator_get_default_mod_mask ();
120 gint increment;
121
122 if ((event->state & modifiers) == GDK_CONTROL_MASK ||
123 (event->state & modifiers) == GDK_MOD1_MASK)
124 return FALSE;
125
126 /* See https://bugs.gnucash.org/show_bug.cgi?id=798386 for semicolon */
127 if (event->keyval == GDK_KEY_plus || event->keyval == GDK_KEY_KP_Add ||
128 event->keyval == GDK_KEY_semicolon)
129 increment = 1;
130 else if (event->keyval == GDK_KEY_minus || event->keyval == GDK_KEY_KP_Subtract)
131 increment = -1;
132 else
133 return FALSE;
134
135 return gnc_dup_inc_dec (widget, text, increment);
136
137 }
138 else
139 return FALSE;
140}
141
142static void
143gnc_dup_trans_dialog_create (GtkWidget * parent, DupTransDialog *dt_dialog,
144 gboolean show_date, time64 date,
145 const char *num_str, const char *tnum_str)
146{
147 GtkWidget *dialog;
148 GtkBuilder *builder;
149 const gchar *tt = _("You can type '+' or '-' to increment or decrement the number.");
150
151 builder = gtk_builder_new ();
152 gnc_builder_add_from_file (builder, "gnc-plugin-page-register.glade", "num_adjustment");
153 gnc_builder_add_from_file (builder, "gnc-plugin-page-register.glade", "tnum_adjustment");
154 gnc_builder_add_from_file (builder, "gnc-plugin-page-register.glade", "duplicate_transaction_dialog");
155
156 dialog = GTK_WIDGET(gtk_builder_get_object (builder, "duplicate_transaction_dialog"));
157 dt_dialog->dialog = dialog;
158
159 // Set the name for this dialog so it can be easily manipulated with css
160 gtk_widget_set_name (GTK_WIDGET(dialog), "gnc-id-duplicate-transaction");
161 gnc_widget_style_context_add_class (GTK_WIDGET(dialog), "gnc-class-transactions");
162
163 /* parent */
164 if (parent != NULL)
165 gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(parent));
166
167 /* date widget */
168 dt_dialog->date_label = GTK_WIDGET(gtk_builder_get_object (builder, "date_label"));
169 if (show_date)
170 {
171 GtkWidget *date_edit;
172 GtkWidget *hbox;
173
174 date_edit = gnc_date_edit_new (date, FALSE, FALSE);
175 gnc_date_activates_default (GNC_DATE_EDIT(date_edit), TRUE);
176 hbox = GTK_WIDGET(gtk_builder_get_object (builder, "date_hbox"));
177 gtk_widget_show (date_edit);
178
179 gnc_date_make_mnemonic_target (GNC_DATE_EDIT(date_edit), dt_dialog->date_label);
180
181 gtk_box_pack_end (GTK_BOX(hbox), date_edit, TRUE, TRUE, 0);
182 dt_dialog->date_edit = date_edit;
183 }
184 else
185 {
186 GtkWidget *date_edit;
187 date_edit = gnc_date_edit_new (date, FALSE, FALSE);
188 dt_dialog->date_edit = date_edit;
189 }
190
191 dt_dialog->duplicate_title_label = GTK_WIDGET(gtk_builder_get_object (builder, "duplicate_title_label"));
192 dt_dialog->duplicate_table = GTK_WIDGET(gtk_builder_get_object (builder, "duplicate_table"));
193 dt_dialog->num_label = GTK_WIDGET(gtk_builder_get_object (builder, "num_label"));
194 dt_dialog->tnum_label = GTK_WIDGET(gtk_builder_get_object (builder, "tnum_label"));
195
196 dt_dialog->num_edit = GTK_WIDGET(gtk_builder_get_object (builder, "num_entry"));
197 dt_dialog->tnum_edit = GTK_WIDGET(gtk_builder_get_object (builder, "tnum_entry"));
198
199 if (num_str)
200 gtk_entry_set_text (GTK_ENTRY(dt_dialog->num_edit), num_str);
201 if (tnum_str)
202 gtk_entry_set_text (GTK_ENTRY(dt_dialog->tnum_edit), tnum_str);
203
204 g_signal_connect (dt_dialog->num_edit, "key-press-event",
205 G_CALLBACK(gnc_dup_key_press_event_cb),
206 dt_dialog);
207
208 g_signal_connect (dt_dialog->tnum_edit, "key-press-event",
209 G_CALLBACK(gnc_dup_key_press_event_cb),
210 dt_dialog);
211
212 if (gnc_strisnum (num_str))
213 {
214 gtk_widget_set_tooltip_text (GTK_WIDGET(dt_dialog->num_edit), tt);
215 gnc_dup_inc_dec (GTK_WIDGET(dt_dialog->num_edit), num_str, 1);
216 }
217 if (gnc_strisnum (tnum_str))
218 {
219 gtk_widget_set_tooltip_text (GTK_WIDGET(dt_dialog->tnum_edit), tt);
220 gnc_dup_inc_dec (GTK_WIDGET(dt_dialog->tnum_edit), tnum_str, 1);
221 }
222
223 /* Transaction Linked Document */
224 {
225 dt_dialog->link_label = GTK_WIDGET(gtk_builder_get_object (builder, "link_label"));
226 dt_dialog->link_edit = GTK_WIDGET(gtk_builder_get_object (builder, "link_check_button"));
227 }
228
229 gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, dt_dialog);
230
231 g_object_unref (G_OBJECT(builder));
232}
233
234static gboolean
235gnc_dup_trans_dialog_internal (GtkWidget * parent,
236 const char* window_title, const char* title,
237 gboolean show_date, time64 *date_p, GDate *gdate_p,
238 const char *num, char **out_num,
239 const char *tnum, char **out_tnum,
240 const char *tlink, char **out_tlink)
241{
242 DupTransDialog *dt_dialog;
243 GtkWidget *entry;
244 gboolean ok;
245 gint result;
246
247 dt_dialog = g_new0 (DupTransDialog, 1);
248
249 gnc_dup_trans_dialog_create (parent, dt_dialog, show_date,
250 *date_p, num, tnum);
251
252 if (!show_date)
253 {
254 // The "date" field isn't being asked for, so we make the widgets invisible
255 gtk_widget_set_visible (dt_dialog->date_label, FALSE);
256 if (dt_dialog->date_edit)
257 gtk_widget_set_visible (dt_dialog->date_edit, FALSE);
258 // If no "date" field, there must be a "num" field, so give it focus
259 if (out_num)
260 gtk_widget_grab_focus (dt_dialog->num_edit);
261 }
262 else
263 {
264 GNCDateEdit *gde;
265
266 gde = GNC_DATE_EDIT(dt_dialog->date_edit);
267 entry = gde->date_entry;
268 gtk_widget_grab_focus (entry);
269 }
270
271 if (window_title)
272 gtk_window_set_title (GTK_WINDOW(dt_dialog->dialog), window_title);
273
274 if (title)
275 {
276 gchar *full_text = g_strdup_printf ("<b>%s</b>", title);
277 gtk_label_set_markup (GTK_LABEL(dt_dialog->duplicate_title_label), full_text);
278 g_free (full_text);
279 }
280
281 if (!out_num)
282 {
283 // The "num" field isn't being asked for, so we make the widgets invisible
284 gtk_widget_set_visible (dt_dialog->num_label, FALSE);
285 gtk_widget_set_visible (dt_dialog->num_edit, FALSE);
286 }
287
288 if (!tnum)
289 {
290 // The "tnum" field isn't being asked for, so we make the widgets invisible
291 gtk_widget_set_visible (dt_dialog->tnum_label, FALSE);
292 gtk_widget_set_visible (dt_dialog->tnum_edit, FALSE);
293 }
294
295 if (!show_date && !tnum)
296 {
297 // The "date" and the "tnum" fields aren't being asked for, this is a split copy
298 gtk_label_set_markup (GTK_LABEL(dt_dialog->num_label), _("Action/Number"));
299 }
300
301 if (tnum)
302 {
303 gtk_entry_set_activates_default (GTK_ENTRY(dt_dialog->num_edit), FALSE);
304 gtk_entry_set_activates_default (GTK_ENTRY(dt_dialog->tnum_edit), TRUE);
305 }
306
307 if (tlink)
308 {
309 gtk_widget_set_visible (dt_dialog->link_label, TRUE);
310 gtk_widget_set_visible (dt_dialog->link_edit, TRUE);
311 }
312 else
313 {
314 gtk_widget_set_visible (dt_dialog->link_label, FALSE);
315 gtk_widget_set_visible (dt_dialog->link_edit, FALSE);
316 }
317
318 result = gtk_dialog_run (GTK_DIALOG(dt_dialog->dialog));
319
320 if (result == GTK_RESPONSE_OK)
321 {
322 if (date_p)
323 *date_p = gnc_date_edit_get_date (GNC_DATE_EDIT(dt_dialog->date_edit));
324 if (gdate_p)
325 gnc_date_edit_get_gdate (GNC_DATE_EDIT(dt_dialog->date_edit), gdate_p);
326 if (out_num)
327 *out_num = g_strdup (gtk_entry_get_text (GTK_ENTRY(dt_dialog->num_edit)));
328 if (tnum)
329 *out_tnum = g_strdup (gtk_entry_get_text (GTK_ENTRY(dt_dialog->tnum_edit)));
330 if (tlink)
331 {
332 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(dt_dialog->link_edit)))
333 *out_tlink = g_strdup (tlink);
334 }
335 ok = TRUE;
336 }
337 else
338 ok = FALSE;
339
340 gtk_widget_destroy (GTK_WIDGET(dt_dialog->dialog));
341 g_free (dt_dialog);
342
343 return ok;
344}
345
346gboolean
347gnc_dup_trans_dialog (GtkWidget * parent, const char* title,
348 gboolean show_date, time64 *date_p,
349 const char *num, char **out_num,
350 const char *tnum, char **out_tnum,
351 const char *tlink, char **out_tlink)
352{
353 return gnc_dup_trans_dialog_internal (parent, NULL, title,
354 show_date, date_p, NULL,
355 num, out_num, tnum, out_tnum,
356 tlink, out_tlink);
357}
358
359gboolean
360gnc_dup_trans_dialog_gdate (GtkWidget * parent, GDate *gdate_p,
361 const char *num, char **out_num)
362{
363 time64 tmp_time;
364 g_assert (gdate_p);
365
366 tmp_time = gdate_to_time64 (*gdate_p);
367 return gnc_dup_trans_dialog_internal (parent, NULL, NULL, TRUE,
368 &tmp_time, gdate_p,
369 num, out_num, NULL, NULL,
370 NULL, NULL);
371}
372
373gboolean
374gnc_dup_time64_dialog (GtkWidget * parent, const char *window_title,
375 const char* title, time64 *date)
376{
377 return gnc_dup_trans_dialog_internal (parent, window_title, title, TRUE,
378 date, NULL,
379 NULL, NULL, NULL, NULL,
380 NULL, NULL);
381}
382
383gboolean
384gnc_dup_date_dialog (GtkWidget * parent, const char* title, GDate *gdate_p)
385{
386 time64 tmp_time;
387 g_assert (gdate_p);
388
389 tmp_time = gdate_to_time64 (*gdate_p);
390 return gnc_dup_trans_dialog_internal (parent, NULL, title, TRUE,
391 &tmp_time, gdate_p,
392 NULL, NULL, NULL, NULL,
393 NULL, NULL);
394}
395
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition gnc-date.h:87
time64 gdate_to_time64(GDate d)
Turns a GDate into a time64, returning the first second of the day.
gboolean gnc_strisnum(const gchar *s)
Returns true if string s is a number, possibly surrounded by whitespace.
Definition qofutil.cpp:187