GnuCash c935c2f+
Loading...
Searching...
No Matches
dialog-doclink.c
1/********************************************************************\
2 * dialog-doclink.c -- Document link dialog *
3 * Copyright (C) 2020 Robert Fewell *
4 * *
5 * This program is free software; you can redistribute it and/or *
6 * modify it under the terms of the GNU General Public License as *
7 * published by the Free Software Foundation; either version 2 of *
8 * the License, or (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License*
16 * along with this program; if not, contact: *
17 * *
18 * Free Software Foundation Voice: +1-617-542-5942 *
19 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
20 * Boston, MA 02110-1301, USA gnu@gnu.org *
21\********************************************************************/
22
23#include <config.h>
24
25#include <gtk/gtk.h>
26#include <glib/gi18n.h>
27
28#include "dialog-doclink.h"
29#include "dialog-doclink-utils.h"
30
31#include "dialog-utils.h"
32#include "gnc-component-manager.h"
33#include "gnc-session.h"
34#include "Transaction.h"
35
38#include "gnc-main-window.h"
39#include "gnc-prefs.h"
40#include "gnc-ui.h"
41#include "gnc-ui-util.h"
42#include "gnc-gnome-utils.h"
43#include "gnc-uri-utils.h"
44#include "gnc-filepath-utils.h"
45#include "Account.h"
46#include "dialog-invoice.h"
47
48#define DIALOG_DOCLINK_CM_CLASS "dialog-doclink"
49#define GNC_PREFS_GROUP_BUS "dialogs.business-doclink"
50#define GNC_PREFS_GROUP_TRANS "dialogs.trans-doclink"
51
53enum GncDoclinkColumn
54{
55 DATE_ITEM,
56 DATE_INT64, // used just for sorting date_trans
57 DESC_ID,
58 DESC_ITEM,
59 DISPLAY_URI,
60 AVAILABLE,
61 ITEM_POINTER,
62 URI,
63 URI_RELATIVE, // used just for sorting relative_pix
64 URI_RELATIVE_PIX
65};
66
67typedef struct
68{
69 GtkWidget *window;
70 GtkWidget *view;
71 GtkWidget *path_head_label;
72 GtkWidget *total_entries_label;
73 gchar *path_head;
74 gboolean is_list_trans;
75 gboolean book_ro;
76 GtkTreeModel *model;
77 gint component_id;
78 QofSession *session;
80
81/* This static indicates the debugging module that this .o belongs to. */
82static QofLogModule log_module = GNC_MOD_GUI;
83
84/* =================================================================== */
85
86void
87gnc_doclink_open_uri (GtkWindow *parent, const gchar *uri)
88{
89 if (uri && *uri)
90 {
91 gchar *scheme = gnc_uri_get_scheme (uri);
92 gchar *path_head = gnc_doclink_get_path_head ();
93 gchar *run_uri = gnc_doclink_get_use_uri (path_head, uri, scheme);
94 gchar *run_scheme = gnc_uri_get_scheme (run_uri);
95
96 PINFO("Open uri scheme is '%s', uri is '%s'", run_scheme, run_uri);
97
98 if (run_scheme) // make sure we have a scheme entry
99 {
100 gnc_launch_doclink (GTK_WINDOW (parent), run_uri);
101 g_free (run_scheme);
102 }
103 g_free (run_uri);
104 g_free (path_head);
105 g_free (scheme);
106 }
107}
108
109/* =================================================================== */
110
111static void
112location_ok_cb (GtkEntry *entry, gpointer user_data)
113{
114 GtkWidget *ok_button = user_data;
115 gboolean have_scheme = FALSE;
116 const gchar *text = gtk_entry_get_text (entry);
117 GtkWidget *warning_hbox = g_object_get_data (G_OBJECT(entry), "whbox");
118
119 if (text && *text)
120 {
121 gchar *scheme = gnc_uri_get_scheme (text);
122
123 if (scheme)
124 have_scheme = TRUE;
125 g_free (scheme);
126 }
127 gtk_widget_set_visible (warning_hbox, !have_scheme);
128 gtk_widget_set_sensitive (ok_button, have_scheme);
129}
130
131static void
132file_ok_cb (GtkButton *button, GtkWidget *ok_button)
133{
134 const gchar *uri = g_object_get_data (G_OBJECT(button), "uri");
135 gboolean file_true = FALSE;
136
137 if (uri)
138 {
139 gchar *full_filename = gnc_uri_get_path (uri);
140
141 /* Test for a valid filename and not a directory */
142 if (full_filename && !g_file_test (full_filename, G_FILE_TEST_IS_DIR))
143 file_true = TRUE;
144
145 g_free (full_filename);
146 }
147 gtk_widget_set_sensitive (ok_button, file_true);
148}
149
150static void
151fcb_clicked_cb (GtkButton *button, GtkWidget *ok_button)
152{
153 GtkWidget *dialog = gtk_widget_get_toplevel (GTK_WIDGET(button));
154 GtkWidget *label = g_object_get_data (G_OBJECT(button), "fcb_label");
155 const gchar *path_head = g_object_get_data (G_OBJECT(button), "path_head");
156 const gchar *uri = g_object_get_data (G_OBJECT(button), "uri");
157 GtkFileChooserNative *native;
158 gint res;
159
160 native = gtk_file_chooser_native_new (_("Select document"),
161 GTK_WINDOW(dialog),
162 GTK_FILE_CHOOSER_ACTION_OPEN,
163 _("_OK"),
164 _("_Cancel"));
165
166 if (uri && *uri)
167 {
168 gchar *scheme = gnc_uri_get_scheme (uri);
169 gchar *full_filename = gnc_doclink_get_unescape_uri (path_head, uri, scheme);
170 gchar *path = g_path_get_dirname (full_filename);
171 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(native), path);
172 g_free (full_filename);
173 g_free (scheme);
174 g_free (path);
175 }
176 else if (path_head)
177 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER(native), path_head);
178
179 res = gtk_native_dialog_run (GTK_NATIVE_DIALOG(native));
180 if (res == GTK_RESPONSE_ACCEPT)
181 {
182 gchar *uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER(native));
183
184 if (uri && *uri)
185 {
186 gchar *filename = g_path_get_basename (uri);
187 gchar *unescape_filename = g_uri_unescape_string (filename, NULL);
188 gtk_label_set_text (GTK_LABEL(label), unescape_filename);
189
190 DEBUG("Native file uri is '%s'", uri);
191
192 g_object_set_data_full (G_OBJECT(button), "uri", g_strdup (uri), g_free);
193 g_free (filename);
194 g_free (unescape_filename);
195 }
196 g_free (uri);
197 file_ok_cb (button, ok_button);
198 }
199 g_object_unref (native);
200}
201
202static void
203uri_type_selected_cb (GtkToggleButton *button, GtkWidget *widget)
204{
205 GtkWidget *top = gtk_widget_get_toplevel (widget);
206 GtkWidget *parent_hbox = gtk_widget_get_parent (widget);
207 GtkWidget *ok_button = g_object_get_data (G_OBJECT(widget), "okbut");
208 gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(button));
209
210 // set the visibility of the parent hbox for widget
211 gtk_widget_set_visible (parent_hbox, active);
212
213 // make the window resize after hiding widgets
214 if (active)
215 {
216 if (g_strcmp0 (gtk_buildable_get_name (
217 GTK_BUILDABLE(parent_hbox)), "location_hbox") == 0)
218 location_ok_cb (GTK_ENTRY (widget), ok_button);
219 else
220 file_ok_cb (GTK_BUTTON(widget), ok_button);
221
222 gtk_window_resize (GTK_WINDOW(top), 600, 10); // width, height
223 }
224}
225
226static void
227setup_location_dialog (GtkBuilder *builder, GtkWidget *button_loc, const gchar *uri)
228{
229 GtkLabel *location_label = GTK_LABEL(gtk_builder_get_object (builder, "location_label"));
230 GtkEntry *entry = GTK_ENTRY(gtk_builder_get_object (builder, "location_entry"));
231 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(button_loc), TRUE);
232
233 // set entry settings
234 gtk_entry_set_width_chars (entry, 80);
235 gtk_entry_set_activates_default (entry, TRUE);
236 gtk_widget_grab_focus (GTK_WIDGET(entry));
237
238 // update label and set entry text if required
239 if (uri)
240 {
241 gtk_label_set_text (location_label, _("Amend the URL"));
242 gtk_entry_set_text (entry, uri);
243 }
244 else
245 {
246 gchar *enter_uri = g_strdup_printf (_("Enter an URL like \"%s\""),
247 PACKAGE_URL);
248 gtk_label_set_text (location_label, enter_uri);
249 g_free (enter_uri);
250 }
251}
252
253static void
254setup_file_dialog (GtkBuilder *builder, const gchar *path_head, const gchar *uri, gchar *scheme)
255{
256 GtkWidget *fcb = GTK_WIDGET(gtk_builder_get_object (builder, "file_chooser_button"));
257 gchar *display_uri = gnc_doclink_get_unescape_uri (path_head, uri, scheme);
258
259 if (display_uri)
260 {
261 GtkWidget *existing_hbox = GTK_WIDGET(gtk_builder_get_object (builder, "existing_hbox"));
262 GtkWidget *image = gtk_image_new_from_icon_name ("dialog-warning", GTK_ICON_SIZE_SMALL_TOOLBAR);
263 gchar *use_uri = gnc_doclink_get_use_uri (path_head, uri, scheme);
264 gchar *uri_label = g_strdup_printf ("%s \"%s\"", _("Existing Document Link is"), display_uri);
265 GtkWidget *label = gtk_label_new (uri_label);
266
267 if (g_file_test (display_uri, G_FILE_TEST_EXISTS))
268 gtk_box_pack_start (GTK_BOX(existing_hbox), label, FALSE, TRUE, 0);
269 else
270 {
271 gtk_box_pack_start (GTK_BOX(existing_hbox), image, FALSE, FALSE, 0);
272 gtk_box_pack_start (GTK_BOX(existing_hbox), label, FALSE, TRUE, 0);
273 }
274
275 PINFO("Path head: '%s', URI: '%s', Filename: '%s'", path_head, uri, display_uri);
276
277 gtk_label_set_ellipsize (GTK_LABEL(label), PANGO_ELLIPSIZE_START);
278
279 // Set the style context for this label so it can be easily manipulated with css
280 gnc_widget_style_context_add_class (GTK_WIDGET(label), "gnc-class-highlight");
281 gtk_widget_show_all (existing_hbox);
282
283 g_free (uri_label);
284 g_free (use_uri);
285 }
286 g_object_set_data_full (G_OBJECT(fcb), "path_head", g_strdup (path_head), g_free);
287 gtk_widget_grab_focus (GTK_WIDGET(fcb));
288 g_free (display_uri);
289}
290
291static gboolean
292gnc_doclink_get_uri_event_cb (GtkWidget *widget, GdkEventKey *event,
293 gpointer user_data)
294{
295 if (event->keyval == GDK_KEY_Escape)
296 {
297 gtk_dialog_response (GTK_DIALOG(widget),
298 GTK_RESPONSE_CANCEL);
299 return TRUE;
300 }
301 return FALSE;
302}
303
304gchar *
305gnc_doclink_get_uri_dialog (GtkWindow *parent, const gchar *title,
306 const gchar *uri)
307{
308 GtkWidget *dialog, *button_loc, *button_file, *ok_button, *warning_hbox;
309 GtkBuilder *builder;
310 gboolean uri_is_file, have_uri = FALSE;
311 GtkEntry *entry;
312 GtkWidget *fcb;
313 GtkWidget *fcb_label;
314 GtkWidget *head_label;
315 int result;
316 gchar *ret_uri = NULL;
317 gchar *path_head = gnc_doclink_get_path_head ();
318 gchar *scheme = NULL;
319
320 /* Create the dialog box */
321 builder = gtk_builder_new();
322 gnc_builder_add_from_file (builder, "dialog-doclink.glade",
323 "linked_doc_dialog");
324 dialog = GTK_WIDGET(gtk_builder_get_object (builder, "linked_doc_dialog"));
325 gtk_window_set_title (GTK_WINDOW(dialog), title);
326
327 if (parent != NULL)
328 gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(parent));
329
330 // Set the name and style context for this widget so it can be easily manipulated with css
331 gtk_widget_set_name (GTK_WIDGET(dialog), "gnc-id-doclink");
332 gnc_widget_style_context_add_class (GTK_WIDGET(dialog), "gnc-class-doclink");
333
334 // Use this event to capture the escape key being pressed
335 g_signal_connect (dialog, "key_press_event",
336 G_CALLBACK(gnc_doclink_get_uri_event_cb), dialog);
337
338 head_label = GTK_WIDGET(gtk_builder_get_object (builder, "path_head_label"));
339 ok_button = GTK_WIDGET(gtk_builder_get_object (builder, "ok_button"));
340
341 fcb = GTK_WIDGET(gtk_builder_get_object (builder, "file_chooser_button"));
342 fcb_label = GTK_WIDGET(gtk_builder_get_object (builder, "file_chooser_button_label"));
343 g_object_set_data (G_OBJECT(fcb), "fcb_label", fcb_label);
344 g_object_set_data (G_OBJECT(fcb), "okbut", ok_button);
345 g_signal_connect (fcb, "clicked", G_CALLBACK(fcb_clicked_cb), ok_button);
346
347 button_file = GTK_WIDGET(gtk_builder_get_object (builder, "linked_file"));
348 g_signal_connect (button_file, "toggled", G_CALLBACK(uri_type_selected_cb), fcb);
349
350 gtk_widget_show_all (GTK_WIDGET(gtk_builder_get_object (builder, "file_hbox")));
351
352 warning_hbox = GTK_WIDGET(gtk_builder_get_object (builder, "warning_hbox"));
353 entry = GTK_ENTRY(gtk_builder_get_object (builder, "location_entry"));
354 g_object_set_data (G_OBJECT(entry), "whbox", warning_hbox);
355 g_object_set_data (G_OBJECT(entry), "okbut", ok_button);
356
357 g_signal_connect (entry, "changed", G_CALLBACK(location_ok_cb), ok_button);
358
359 button_loc = GTK_WIDGET(gtk_builder_get_object (builder, "linked_loc"));
360 g_signal_connect (button_loc, "toggled", G_CALLBACK(uri_type_selected_cb), entry);
361
362 // display path head text and test if present
363 gnc_doclink_set_path_head_label (head_label, NULL, NULL);
364
365 // Check for uri is empty or NULL
366 if (uri && *uri)
367 {
368 scheme = gnc_uri_get_scheme (uri);
369 have_uri = TRUE;
370
371 if (!scheme || g_strcmp0 (scheme, "file") == 0) // use the correct dialog
372 uri_is_file = TRUE;
373 else
374 uri_is_file = FALSE;
375 }
376 else
377 {
378 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(button_loc), TRUE);
379 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(button_file), TRUE);
380 }
381
382 // make sure we start with the right dialog
383 if (have_uri)
384 {
385 if (uri_is_file) // file
386 {
387 gchar *filename = g_path_get_basename (uri);
388
389 g_object_set_data_full (G_OBJECT(fcb), "uri", g_strdup (uri), g_free);
390
391 if (filename)
392 {
393 gchar *unescape_filename = g_uri_unescape_string (filename, NULL);
394 gtk_label_set_text (GTK_LABEL(fcb_label), unescape_filename);
395 g_free (unescape_filename);
396 g_free (filename);
397 }
398 setup_file_dialog (builder, path_head, uri, scheme);
399 }
400 else // location
401 setup_location_dialog (builder, button_loc, uri);
402 }
403 else
404 g_object_set_data_full (G_OBJECT(fcb), "path_head", g_strdup (path_head), g_free);
405
406 g_free (scheme);
407 g_object_unref (G_OBJECT(builder));
408
409 // run the dialog
410 result = gtk_dialog_run (GTK_DIALOG(dialog));
411 if (result == GTK_RESPONSE_OK) //ok button
412 {
413 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(button_loc))) // location
414 {
415 const gchar *dialog_uri = gtk_entry_get_text (GTK_ENTRY(entry));
416
417 ret_uri = g_strdup (dialog_uri);
418
419 DEBUG("Dialog Location URI: '%s'", dialog_uri);
420 }
421 else // file
422 {
423 const gchar *dialog_uri = g_object_get_data (G_OBJECT(fcb), "uri");
424
425 PINFO("Dialog File URI: '%s', Path head: '%s'", dialog_uri, path_head);
426
427 // relative paths do not start with a '/'
428 if (g_str_has_prefix (dialog_uri, path_head))
429 {
430 const gchar *part = dialog_uri + strlen (path_head);
431 ret_uri = g_strdup (part);
432 }
433 else
434 ret_uri = g_strdup (dialog_uri);
435
436 DEBUG("Dialog File URI: '%s'", ret_uri);
437 }
438 }
439 else if (result == GTK_RESPONSE_REJECT) // remove button
440 ret_uri = g_strdup ("");
441 else
442 ret_uri = g_strdup (uri); // any other button
443
444 g_free (path_head);
445 gtk_widget_destroy (dialog);
446 return ret_uri;
447}
448
449
450/* =================================================================== */
451
452
453static void close_handler (gpointer user_data);
454
455static gboolean
456gnc_doclink_dialog_window_delete_event_cb (GtkWidget *widget,
457 GdkEvent *event,
458 gpointer user_data)
459{
460 DoclinkDialog *doclink_dialog = user_data;
461 // this cb allows the window size to be saved on closing with the X
462 if (doclink_dialog->is_list_trans)
463 gnc_save_window_size (GNC_PREFS_GROUP_TRANS,
464 GTK_WINDOW(doclink_dialog->window));
465 else
466 gnc_save_window_size (GNC_PREFS_GROUP_BUS,
467 GTK_WINDOW(doclink_dialog->window));
468 return FALSE;
469}
470
471static void
472gnc_doclink_dialog_window_destroy_cb (GtkWidget *object, gpointer user_data)
473{
474 DoclinkDialog *doclink_dialog = user_data;
475
476 ENTER(" ");
477 gnc_unregister_gui_component (doclink_dialog->component_id);
478
479 if (doclink_dialog->window)
480 {
481 g_free (doclink_dialog->path_head);
482 gtk_widget_destroy (doclink_dialog->window);
483 doclink_dialog->window = NULL;
484 }
485 g_free (doclink_dialog);
486 LEAVE(" ");
487}
488
489static gboolean
490gnc_doclink_dialog_window_key_press_cb (GtkWidget *widget, GdkEventKey *event,
491 gpointer user_data)
492{
493 DoclinkDialog *doclink_dialog = user_data;
494
495 if (event->keyval == GDK_KEY_Escape)
496 {
497 close_handler (doclink_dialog);
498 return TRUE;
499 }
500 else
501 return FALSE;
502}
503
504static void
505doclink_dialog_update (DoclinkDialog *doclink_dialog)
506{
507 GtkTreeModel *model;
508 GtkTreeIter iter;
509 gboolean valid;
510
511 /* disconnect the model from the treeview */
512 model = gtk_tree_view_get_model (GTK_TREE_VIEW (doclink_dialog->view));
513 g_object_ref (G_OBJECT(model));
514 gtk_tree_view_set_model (GTK_TREE_VIEW (doclink_dialog->view), NULL);
515
516 /* Get first row in list store */
517 valid = gtk_tree_model_get_iter_first (model, &iter);
518
519 while (valid)
520 {
521 gchar *uri;
522 gchar *scheme;
523
524 gtk_tree_model_get (model, &iter, URI, &uri, -1);
525
526 scheme = gnc_uri_get_scheme (uri);
527
528 if (!scheme || gnc_uri_is_file_scheme (scheme))
529 {
530 gchar *filename =
531 gnc_doclink_get_unescape_uri (doclink_dialog->path_head,
532 uri, scheme);
533
534 if (g_file_test (filename, G_FILE_TEST_EXISTS))
535 gtk_list_store_set (GTK_LIST_STORE(model), &iter, AVAILABLE, _("File Found"), -1);
536 else
537 gtk_list_store_set (GTK_LIST_STORE(model), &iter, AVAILABLE, _("File Not Found"), -1);
538
539 g_free (filename);
540 }
541 else
542 {
543 gchar *escaped = g_uri_escape_string (uri, ":/.", TRUE);
544 GNetworkMonitor *nm = g_network_monitor_get_default ();
545 GSocketConnectable *conn = g_network_address_parse_uri (escaped, 80, NULL);
546
547 if (conn)
548 {
549 if (g_network_monitor_can_reach (nm, conn, NULL, NULL))
550 gtk_list_store_set (GTK_LIST_STORE(model), &iter, AVAILABLE, _("Address Found"), -1);
551 else
552 gtk_list_store_set (GTK_LIST_STORE(model), &iter, AVAILABLE, _("Address Not Found"), -1);
553 }
554 g_free (escaped);
555 }
556 g_free (uri);
557 g_free (scheme);
558
559 valid = gtk_tree_model_iter_next (model, &iter);
560 }
561 /* reconnect the model to the treeview */
562 gtk_tree_view_set_model (GTK_TREE_VIEW (doclink_dialog->view), model);
563 g_object_unref (G_OBJECT(model));
564}
565
566static void
567update_model_with_changes (DoclinkDialog *doclink_dialog, GtkTreeIter *iter,
568 const gchar *uri)
569{
570 gchar *display_uri;
571 gboolean rel = FALSE;
572 gchar *scheme = gnc_uri_get_scheme (uri);
573
574 if (!scheme) // path is relative
575 rel = TRUE;
576
577 display_uri = gnc_doclink_get_unescape_uri (doclink_dialog->path_head,
578 uri, scheme);
579 gtk_list_store_set (GTK_LIST_STORE (doclink_dialog->model), iter,
580 DISPLAY_URI, display_uri, AVAILABLE, _("File Found"),
581 URI, uri,
582 URI_RELATIVE, rel, // used just for sorting relative column
583 URI_RELATIVE_PIX, (rel == TRUE ? "emblem-default" : NULL), -1);
584
585 if (!rel && !gnc_uri_is_file_scheme (scheme))
586 gtk_list_store_set (GTK_LIST_STORE (doclink_dialog->model), iter,
587 AVAILABLE, _("Unknown"), -1);
588
589 g_free (display_uri);
590 g_free (scheme);
591}
592
593static void
594update_total_entries (DoclinkDialog *doclink_dialog)
595{
596 gint entries =
597 gtk_tree_model_iter_n_children (GTK_TREE_MODEL (doclink_dialog->model),
598 NULL);
599
600 if (entries > 0)
601 {
602 gchar *total = g_strdup_printf ("%s %d", _("Total Entries"), entries);
603 gtk_label_set_text (GTK_LABEL (doclink_dialog->total_entries_label),
604 total);
605 gtk_widget_show (doclink_dialog->total_entries_label);
606 g_free (total);
607 }
608 else
609 gtk_widget_hide (doclink_dialog->total_entries_label);
610}
611
612static void
613row_selected_bus_cb (GtkTreeView *view, GtkTreePath *path,
614 GtkTreeViewColumn *col, gpointer user_data)
615{
616 DoclinkDialog *doclink_dialog = user_data;
617 GtkTreeIter iter;
618 GncInvoice *invoice;
619 gchar *uri = NULL;
620
621 // path describes a non-existing row - should not happen
622 g_return_if_fail (gtk_tree_model_get_iter (doclink_dialog->model,
623 &iter, path));
624
625 gtk_tree_model_get (doclink_dialog->model, &iter, URI,
626 &uri, ITEM_POINTER, &invoice, -1);
627
628 // Open linked document, subtract 1 to allow for date_int64
629 if (gtk_tree_view_get_column (GTK_TREE_VIEW (doclink_dialog->view),
630 DISPLAY_URI - 1) == col)
631 gnc_doclink_open_uri (GTK_WINDOW (doclink_dialog->window), uri);
632
633 if (!invoice)
634 {
635 g_free (uri);
636 return;
637 }
638
639 // Open Invoice, subtract 1 to allow for date_int64
640 if (gtk_tree_view_get_column (GTK_TREE_VIEW (doclink_dialog->view),
641 DESC_ID - 1) == col)
642 {
643 InvoiceWindow *iw;
644
645 iw = gnc_ui_invoice_edit (GTK_WINDOW (doclink_dialog->window),
646 invoice);
648 }
649
650 // Open Invoice document link dialog, subtract 1 to allow for date_int64
651 if (gtk_tree_view_get_column (GTK_TREE_VIEW (doclink_dialog->view),
652 AVAILABLE - 1) == col)
653 {
654 gchar *ret_uri = NULL;
655
656 if (doclink_dialog->book_ro)
657 {
658 gnc_warning_dialog (GTK_WINDOW (doclink_dialog->window), "%s",
659 _("Business item can not be modified."));
660 g_free (uri);
661 return;
662 }
663
664/* Translators: This is the title of a dialog box for linking an external
665 file or URI with the current bill, invoice, transaction, or voucher. */
666 ret_uri =
667 gnc_doclink_get_uri_dialog (GTK_WINDOW (doclink_dialog->window),
668 _("Manage Document Link"), uri);
669
670 if (ret_uri && g_strcmp0 (uri, ret_uri) != 0)
671 {
672 gncInvoiceSetDocLink (invoice, ret_uri);
673
674 if (g_strcmp0 (ret_uri, "") == 0) // delete uri
675 {
676 // update the asooc parts for invoice window if present
677 gnc_invoice_update_doclink_for_window (invoice, ret_uri);
678 gtk_list_store_remove (GTK_LIST_STORE (doclink_dialog->model),
679 &iter);
680 update_total_entries (doclink_dialog);
681 }
682 else // update uri
683 {
684 gchar *display_uri;
685 gchar *scheme = gnc_uri_get_scheme (ret_uri);
686
687 display_uri = gnc_doclink_get_unescape_uri (doclink_dialog->path_head, ret_uri, scheme);
688
689 update_model_with_changes (doclink_dialog, &iter, ret_uri);
690
691 // update the asooc parts for invoice window if present
692 gnc_invoice_update_doclink_for_window (invoice, display_uri);
693
694 g_free (scheme);
695 g_free (display_uri);
696 }
697 }
698 g_free (ret_uri);
699 }
700 g_free (uri);
701}
702
703static void
704row_selected_trans_cb (GtkTreeView *view, GtkTreePath *path,
705 GtkTreeViewColumn *col, gpointer user_data)
706{
707 DoclinkDialog *doclink_dialog = user_data;
708 GtkTreeIter iter;
709 Split *split;
710 gchar *uri = NULL;
711
712 // path describes a non-existing row - should not happen
713 g_return_if_fail (gtk_tree_model_get_iter (doclink_dialog->model,
714 &iter, path));
715
716 gtk_tree_model_get (doclink_dialog->model, &iter, URI,
717 &uri, ITEM_POINTER, &split, -1);
718
719 // Open linked document, subtract 1 to allow for date_int64
720 if (gtk_tree_view_get_column (GTK_TREE_VIEW (doclink_dialog->view),
721 DISPLAY_URI - 1) == col)
722 gnc_doclink_open_uri (GTK_WINDOW (doclink_dialog->window), uri);
723
724 if (!split)
725 {
726 g_free (uri);
727 return;
728 }
729
730 // Open transaction, subtract 1 to allow for date_int64
731 if (gtk_tree_view_get_column (GTK_TREE_VIEW(doclink_dialog->view),
732 DESC_ITEM - 1) == col)
733 {
734 GncPluginPage *page;
735 GNCSplitReg *gsr;
736 Account *account = xaccSplitGetAccount (split);
737
738 page = gnc_plugin_page_register_new (account, FALSE);
739 gnc_main_window_open_page (NULL, page);
741 gnc_split_reg_raise (gsr);
742
743 // Test for visibility of split
744 if (gnc_split_reg_clear_filter_for_split (gsr, split))
745 gnc_plugin_page_register_clear_current_filter (GNC_PLUGIN_PAGE(page));
746
747 gnc_split_reg_jump_to_split (gsr, split);
748 }
749
750 // Open transaction document link dialog, subtract 1 to allow for date_int64
751 if (gtk_tree_view_get_column (GTK_TREE_VIEW(doclink_dialog->view), AVAILABLE - 1) == col)
752 {
753 Transaction *trans;
754 gchar *ret_uri = NULL;
755
756 trans = xaccSplitGetParent (split);
757
759 xaccTransGetReadOnly (trans) ||
760 doclink_dialog->book_ro)
761 {
762 gnc_warning_dialog (GTK_WINDOW (doclink_dialog->window), "%s",
763 _("Transaction can not be modified."));
764 g_free (uri);
765 return;
766 }
767 ret_uri =
768 gnc_doclink_get_uri_dialog (GTK_WINDOW (doclink_dialog->window),
769 _("Manage Document Link"), uri);
770
771 if (ret_uri && g_strcmp0 (uri, ret_uri) != 0)
772 {
773 xaccTransSetDocLink (trans, ret_uri);
774 if (g_strcmp0 (ret_uri, "") == 0) // deleted uri
775 {
776 gtk_list_store_remove (GTK_LIST_STORE (doclink_dialog->model),
777 &iter);
778 update_total_entries (doclink_dialog);
779 }
780 else // updated uri
781 update_model_with_changes (doclink_dialog, &iter, ret_uri);
782 }
783 g_free (ret_uri);
784 }
785 g_free (uri);
786}
787
788static void
789add_bus_info_to_model (QofInstance* data, gpointer user_data)
790{
791 DoclinkDialog *doclink_dialog = user_data;
792 GncInvoice *invoice = GNC_INVOICE(data);
793 const gchar *uri = gncInvoiceGetDocLink (invoice);
794 GtkTreeIter iter;
795
796 if (uri && *uri)
797 {
798 gchar *display_uri;
799 gboolean rel = FALSE;
800 gchar *scheme = gnc_uri_get_scheme (uri);
801 time64 t = gncInvoiceGetDateOpened (invoice);
802 gchar *inv_type;
803 char datebuff[MAX_DATE_LENGTH + 1];
804 memset (datebuff, 0, sizeof(datebuff));
805 if (t == 0)
806 t = gnc_time (NULL);
807 qof_print_date_buff (datebuff, sizeof(datebuff), t);
808
809 switch (gncInvoiceGetType (invoice))
810 {
811 case GNC_INVOICE_VEND_INVOICE:
812 case GNC_INVOICE_VEND_CREDIT_NOTE:
813 inv_type = _("Bill");
814 break;
815 case GNC_INVOICE_EMPL_INVOICE:
816 case GNC_INVOICE_EMPL_CREDIT_NOTE:
817 inv_type = _("Voucher");
818 break;
819 case GNC_INVOICE_CUST_INVOICE:
820 case GNC_INVOICE_CUST_CREDIT_NOTE:
821 inv_type = _("Invoice");
822 break;
823 default:
824 inv_type = _("Undefined");
825 }
826
827 if (!scheme) // path is relative
828 rel = TRUE;
829
830 display_uri = gnc_doclink_get_unescape_uri (doclink_dialog->path_head,
831 uri, scheme);
832
833 gtk_list_store_append (GTK_LIST_STORE (doclink_dialog->model), &iter);
834
835 gtk_list_store_set (GTK_LIST_STORE (doclink_dialog->model), &iter,
836 DATE_ITEM, datebuff,
837 DATE_INT64, t, // used just for sorting date column
838 DESC_ID, gncInvoiceGetID (invoice),
839 DESC_ITEM, inv_type,
840 DISPLAY_URI, display_uri, AVAILABLE, _("Unknown"),
841 ITEM_POINTER, invoice, URI, uri,
842 URI_RELATIVE, rel, // used just for sorting relative column
843 URI_RELATIVE_PIX, (rel == TRUE ? "emblem-default" : NULL), -1);
844 g_free (display_uri);
845 g_free (scheme);
846 }
847}
848
849static void
850add_trans_info_to_model (QofInstance* data, gpointer user_data)
851{
852 DoclinkDialog *doclink_dialog = user_data;
853 Transaction *trans = GNC_TRANSACTION(data);
854 gchar *uri;
855 GtkTreeIter iter;
856
857 // fix an earlier error when storing relative paths before version 3.5
858 uri = gnc_doclink_convert_trans_link_uri (trans, doclink_dialog->book_ro);
859
860 if (uri && *uri)
861 {
862 Split *split = xaccTransGetSplit (trans, 0);
863 gchar *scheme = gnc_uri_get_scheme (uri);
864 gchar *display_uri;
865 gboolean rel = FALSE;
866 time64 t = xaccTransRetDatePosted (trans);
867 char datebuff[MAX_DATE_LENGTH + 1];
868 memset (datebuff, 0, sizeof(datebuff));
869 if (t == 0)
870 t = gnc_time (NULL);
872 gtk_list_store_append (GTK_LIST_STORE (doclink_dialog->model), &iter);
873
874 if (!scheme) // path is relative
875 rel = TRUE;
876
877 display_uri = gnc_doclink_get_unescape_uri (doclink_dialog->path_head,
878 uri, scheme);
879
880 gtk_list_store_set (GTK_LIST_STORE (doclink_dialog->model), &iter,
881 DATE_ITEM, datebuff,
882 DATE_INT64, t, // used just for sorting date column
883 DESC_ITEM, xaccTransGetDescription (trans),
884 DISPLAY_URI, display_uri, AVAILABLE, _("Unknown"),
885 ITEM_POINTER, split, URI, uri,
886 URI_RELATIVE, rel, // used just for sorting relative column
887 URI_RELATIVE_PIX, (rel == TRUE ? "emblem-default" : NULL), -1);
888 g_free (display_uri);
889 g_free (scheme);
890 g_free (uri);
891 }
892}
893
894static void
895get_bus_info (DoclinkDialog *doclink_dialog)
896{
897 QofBook *book = gnc_get_current_book();
898
899 /* disconnect the model from the treeview */
900 doclink_dialog->model =
901 gtk_tree_view_get_model (GTK_TREE_VIEW (doclink_dialog->view));
902 g_object_ref (G_OBJECT (doclink_dialog->model));
903 gtk_tree_view_set_model (GTK_TREE_VIEW (doclink_dialog->view), NULL);
904
905 /* Clear the list store */
906 gtk_list_store_clear (GTK_LIST_STORE (doclink_dialog->model));
907
908 /* Loop through the invoices */
909 qof_collection_foreach (qof_book_get_collection (book, GNC_ID_INVOICE),
910 add_bus_info_to_model, doclink_dialog);
911
912 update_total_entries (doclink_dialog);
913
914 /* reconnect the model to the treeview */
915 gtk_tree_view_set_model (GTK_TREE_VIEW (doclink_dialog->view),
916 doclink_dialog->model);
917 g_object_unref (G_OBJECT (doclink_dialog->model));
918}
919
920static void
921get_trans_info (DoclinkDialog *doclink_dialog)
922{
923 QofBook *book = gnc_get_current_book();
924
925 doclink_dialog->book_ro = qof_book_is_readonly (book);
926
927 /* disconnect the model from the treeview */
928 doclink_dialog->model =
929 gtk_tree_view_get_model (GTK_TREE_VIEW (doclink_dialog->view));
930 g_object_ref (G_OBJECT (doclink_dialog->model));
931 gtk_tree_view_set_model (GTK_TREE_VIEW (doclink_dialog->view), NULL);
932
933 /* Clear the list store */
934 gtk_list_store_clear (GTK_LIST_STORE (doclink_dialog->model));
935
936 /* Loop through the transactions */
937 qof_collection_foreach (qof_book_get_collection (book, GNC_ID_TRANS),
938 add_trans_info_to_model, doclink_dialog);
939
940 update_total_entries (doclink_dialog);
941
942 /* reconnect the model to the treeview */
943 gtk_tree_view_set_model (GTK_TREE_VIEW (doclink_dialog->view),
944 doclink_dialog->model);
945 g_object_unref (G_OBJECT (doclink_dialog->model));
946}
947
948static void
949gnc_doclink_dialog_reload_button_cb (GtkWidget *widget, gpointer user_data)
950{
951 DoclinkDialog *doclink_dialog = user_data;
952 gchar *path_head = gnc_doclink_get_path_head ();
953
954 if (g_strcmp0 (path_head, doclink_dialog->path_head) != 0)
955 {
956 g_free (doclink_dialog->path_head);
957 doclink_dialog->path_head = g_strdup (path_head);
958
959 // display path head text and test if present
960 gnc_doclink_set_path_head_label (doclink_dialog->path_head_label,
961 NULL, NULL);
962 }
963 g_free (path_head);
964
965 if (doclink_dialog->is_list_trans)
966 get_trans_info (doclink_dialog);
967 else
968 get_bus_info (doclink_dialog);
969}
970
971static void
972gnc_doclink_dialog_reload_check_button_cb (GtkWidget *widget,
973 gpointer user_data)
974{
975 DoclinkDialog *doclink_dialog = user_data;
976
977 gnc_doclink_dialog_reload_button_cb (widget, user_data);
978 doclink_dialog_update (doclink_dialog);
979}
980
981static void
982gnc_doclink_dialog_check_button_cb (GtkWidget *widget, gpointer user_data)
983{
984 DoclinkDialog *doclink_dialog = user_data;
985 doclink_dialog_update (doclink_dialog);
986}
987
988static void
989gnc_doclink_dialog_close_button_cb (GtkWidget *widget, gpointer user_data)
990{
991 DoclinkDialog *doclink_dialog = user_data;
992 gnc_close_gui_component (doclink_dialog->component_id);
993}
994
995static void
996gnc_doclink_dialog_create (GtkWindow *parent, DoclinkDialog *doclink_dialog)
997{
998 GtkWidget *window;
999 GtkBuilder *builder;
1000 GtkTreeSelection *selection;
1001 GtkTreeViewColumn *expanding_column;
1002 GtkWidget *button;
1003
1004 ENTER(" ");
1005 builder = gtk_builder_new();
1006 gnc_builder_add_from_file (builder, "dialog-doclink.glade", "list-store");
1007 gnc_builder_add_from_file (builder, "dialog-doclink.glade",
1008 "linked_doc_window");
1009
1010 window = GTK_WIDGET(gtk_builder_get_object (builder, "linked_doc_window"));
1011 doclink_dialog->window = window;
1012 doclink_dialog->session = gnc_get_current_session();
1013
1014 button = GTK_WIDGET(gtk_builder_get_object (builder, "reload_button"));
1015 g_signal_connect (button, "clicked",
1016 G_CALLBACK (gnc_doclink_dialog_reload_button_cb),
1017 doclink_dialog);
1018 button = GTK_WIDGET(gtk_builder_get_object (builder, "reload_and_check_button"));
1019 g_signal_connect (button, "clicked",
1020 G_CALLBACK (gnc_doclink_dialog_reload_check_button_cb),
1021 doclink_dialog);
1022
1023 button = GTK_WIDGET(gtk_builder_get_object (builder, "check_button"));
1024 g_signal_connect (button, "clicked",
1025 G_CALLBACK (gnc_doclink_dialog_check_button_cb),
1026 doclink_dialog);
1027 button = GTK_WIDGET(gtk_builder_get_object (builder, "close_button"));
1028 g_signal_connect (button, "clicked",
1029 G_CALLBACK (gnc_doclink_dialog_close_button_cb),
1030 doclink_dialog);
1031
1032 // Set the widget name and style context for this dialog so it can be easily manipulated with css
1033 gtk_widget_set_name (GTK_WIDGET (window), "gnc-id-transaction-doclinks");
1034 gnc_widget_style_context_add_class (GTK_WIDGET (window),
1035 "gnc-class-doclink");
1036
1037 doclink_dialog->view =
1038 GTK_WIDGET (gtk_builder_get_object (builder, "treeview"));
1039 doclink_dialog->path_head_label =
1040 GTK_WIDGET (gtk_builder_get_object (builder, "path-head"));
1041 doclink_dialog->total_entries_label =
1042 GTK_WIDGET (gtk_builder_get_object (builder, "total_entries_label"));
1043 doclink_dialog->path_head = gnc_doclink_get_path_head ();
1044
1045 // display path head text and test if present
1046 gnc_doclink_set_path_head_label (doclink_dialog->path_head_label, NULL, NULL);
1047
1048 // Get the column we want to be the expanding column.
1049 expanding_column =
1050 GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (builder, "doclink"));
1051
1052 /* default sort order */
1053 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(gtk_tree_view_get_model(
1054 GTK_TREE_VIEW (doclink_dialog->view))),
1055 DATE_INT64, GTK_SORT_ASCENDING);
1056
1057 // Set grid lines option to preference
1058 gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (doclink_dialog->view),
1059 gnc_tree_view_get_grid_lines_pref ());
1060
1061 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (doclink_dialog->view));
1062 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
1063
1064 g_signal_connect (doclink_dialog->window, "destroy",
1065 G_CALLBACK (gnc_doclink_dialog_window_destroy_cb),
1066 doclink_dialog);
1067
1068 g_signal_connect (doclink_dialog->window, "delete-event",
1069 G_CALLBACK(gnc_doclink_dialog_window_delete_event_cb), doclink_dialog);
1070
1071 g_signal_connect (doclink_dialog->window, "key_press_event",
1072 G_CALLBACK (gnc_doclink_dialog_window_key_press_cb),
1073 doclink_dialog);
1074
1075 // Setup the correct parts for each dialog
1076 if (doclink_dialog->is_list_trans)
1077 {
1078 GObject *desc_item_tree_column = G_OBJECT(gtk_builder_get_object (builder, "desc_item"));
1079 GObject *desc_id_tree_column = G_OBJECT(gtk_builder_get_object (builder, "desc_id"));
1080
1081 /* Translators: This is the label of a dialog box that lists all of the
1082 transaction that have files or URIs linked with them. */
1083 gtk_window_set_title (GTK_WINDOW (window), _("Transaction Document Links"));
1084
1085 gtk_tree_view_column_set_visible (GTK_TREE_VIEW_COLUMN(desc_id_tree_column), FALSE);
1086 gtk_tree_view_column_set_title (GTK_TREE_VIEW_COLUMN(desc_item_tree_column), _("Description"));
1087
1088 g_signal_connect (doclink_dialog->view, "row-activated",
1089 G_CALLBACK (row_selected_trans_cb),
1090 (gpointer)doclink_dialog);
1091 get_trans_info (doclink_dialog);
1092 }
1093 else
1094 {
1095 GtkWidget *help_label = GTK_WIDGET(gtk_builder_get_object (builder, "help_label"));
1096 const gchar *item_string = N_(
1097 "Double click on the entry in the Id column to jump to the "
1098 "Business Item.\nDouble click on the entry in the Link column "
1099 "to open the Linked Document.\nDouble click on the entry in "
1100 "the Available column to modify the document link.");
1101
1102 /* Translators: This is the label of a dialog box that lists all of the
1103 invoices, bills, and vouchers that have files or URIs linked with
1104 them. */
1105 gtk_window_set_title (GTK_WINDOW (doclink_dialog->window),
1106 _("Business Document Links"));
1107 gtk_label_set_text (GTK_LABEL(help_label), gettext (item_string));
1108
1109 g_signal_connect (doclink_dialog->view, "row-activated",
1110 G_CALLBACK (row_selected_bus_cb),
1111 (gpointer)doclink_dialog);
1112 get_bus_info (doclink_dialog);
1113 }
1114
1115 gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func,
1116 doclink_dialog);
1117
1118 g_object_unref (G_OBJECT(builder));
1119
1120 gtk_tree_view_column_set_expand (expanding_column, TRUE);
1121 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(doclink_dialog->view));
1122 LEAVE(" ");
1123}
1124
1125static void
1126close_handler (gpointer user_data)
1127{
1128 DoclinkDialog *doclink_dialog = user_data;
1129
1130 ENTER(" ");
1131 if (doclink_dialog->is_list_trans)
1132 gnc_save_window_size (GNC_PREFS_GROUP_TRANS,
1133 GTK_WINDOW (doclink_dialog->window));
1134 else
1135 gnc_save_window_size (GNC_PREFS_GROUP_BUS,
1136 GTK_WINDOW (doclink_dialog->window));
1137 gtk_widget_destroy (GTK_WIDGET (doclink_dialog->window));
1138 LEAVE(" ");
1139}
1140
1141static void
1142refresh_handler (GHashTable *changes, gpointer user_data)
1143{
1144 ENTER(" ");
1145 LEAVE(" ");
1146}
1147
1148static gboolean
1149show_handler (const char *klass, gint component_id,
1150 gpointer user_data, gpointer iter_data)
1151{
1152 DoclinkDialog *doclink_dialog = user_data;
1153 gboolean is_bus = GPOINTER_TO_INT(iter_data);
1154
1155 ENTER(" ");
1156 if (!doclink_dialog)
1157 {
1158 LEAVE("No data structure");
1159 return (FALSE);
1160 }
1161
1162 // test if the dialog is the right one
1163 if (is_bus == doclink_dialog->is_list_trans)
1164 return (FALSE);
1165
1166 gtk_window_present (GTK_WINDOW(doclink_dialog->window));
1167 LEAVE(" ");
1168 return (TRUE);
1169}
1170
1171void
1172gnc_doclink_business_dialog (GtkWindow *parent)
1173{
1174 DoclinkDialog *doclink_dialog;
1175
1176 ENTER(" ");
1177 if (gnc_forall_gui_components (DIALOG_DOCLINK_CM_CLASS,
1178 show_handler, GINT_TO_POINTER(1)))
1179 {
1180 LEAVE("Existing dialog raised");
1181 return;
1182 }
1183 doclink_dialog = g_new0 (DoclinkDialog, 1);
1184
1185 doclink_dialog->is_list_trans = FALSE;
1186
1187 gnc_doclink_dialog_create (parent, doclink_dialog);
1188
1189 doclink_dialog->component_id =
1190 gnc_register_gui_component (DIALOG_DOCLINK_CM_CLASS,
1191 refresh_handler, close_handler,
1192 doclink_dialog);
1193
1194 gnc_gui_component_set_session (doclink_dialog->component_id,
1195 doclink_dialog->session);
1196
1197 gnc_restore_window_size (GNC_PREFS_GROUP_BUS,
1198 GTK_WINDOW(doclink_dialog->window), parent);
1199 gtk_widget_show_all (GTK_WIDGET(doclink_dialog->window));
1200 LEAVE(" ");
1201}
1202
1203void
1204gnc_doclink_trans_dialog (GtkWindow *parent)
1205{
1206 DoclinkDialog *doclink_dialog;
1207
1208 ENTER(" ");
1209 if (gnc_forall_gui_components (DIALOG_DOCLINK_CM_CLASS,
1210 show_handler, GINT_TO_POINTER(0)))
1211 {
1212 LEAVE("Existing dialog raised");
1213 return;
1214 }
1215 doclink_dialog = g_new0 (DoclinkDialog, 1);
1216 doclink_dialog->is_list_trans = TRUE;
1217
1218 gnc_doclink_dialog_create (parent, doclink_dialog);
1219
1220 doclink_dialog->component_id =
1221 gnc_register_gui_component (DIALOG_DOCLINK_CM_CLASS,
1222 refresh_handler, close_handler,
1223 doclink_dialog);
1224
1225 gnc_gui_component_set_session (doclink_dialog->component_id,
1226 doclink_dialog->session);
1227
1228 gnc_restore_window_size (GNC_PREFS_GROUP_TRANS,
1229 GTK_WINDOW(doclink_dialog->window), parent);
1230 gtk_widget_show_all (GTK_WIDGET(doclink_dialog->window));
1231 LEAVE(" ");
1232}
Account handling public routines.
API for Transactions and Splits (journal entries)
File path resolution utility functions.
Gnome specific utility functions.
Functions for adding content to a window.
utility functions for the GnuCash UI
Functions providing a register page for the GnuCash UI.
Generic api to store and retrieve preferences.
utility functions for the GnuCash UI
Utility functions for convert uri in separate components and back.
QofCollection * qof_book_get_collection(const QofBook *book, QofIdType entity_type)
Return The table of entities of the given type.
Definition qofbook.cpp:521
gboolean qof_book_is_readonly(const QofBook *book)
Return whether the book is read only.
Definition qofbook.cpp:497
#define MAX_DATE_LENGTH
The maximum length of a string created by the date printers.
Definition gnc-date.h:108
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition gnc-date.h:87
size_t qof_print_date_buff(char *buff, const size_t len, time64 t)
Convenience: calls through to qof_print_date_dmy_buff().
Definition gnc-date.cpp:574
time64 gnc_time(time64 *tbuf)
get the current time
Definition gnc-date.cpp:262
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
Split * xaccTransGetSplit(const Transaction *trans, int i)
Return a pointer to the indexed split in this transaction's split list.
time64 xaccTransRetDatePosted(const Transaction *trans)
Retrieve the posted date of the transaction.
void xaccTransSetDocLink(Transaction *trans, const char *doclink)
Sets the transaction Document Link.
gboolean xaccTransIsReadonlyByPostedDate(const Transaction *trans)
Returns TRUE if this Transaction is read-only because its posted-date is older than the "auto-readonl...
const char * xaccTransGetReadOnly(Transaction *trans)
Returns a non-NULL value if this Transaction was marked as read-only with some specific "reason" text...
void gnc_main_window_open_page(GncMainWindow *window, GncPluginPage *page)
Display a data plugin page in a window.
void gnc_launch_doclink(GtkWindow *parent, const char *uri)
Launch the default browser and open the provided URI.
GncPluginPage * gnc_plugin_page_invoice_new(InvoiceWindow *iw)
Create a new "invoice" plugin page, given a pointer to an InvoiceWindow data structure.
#define PINFO(format, args...)
Print an informational note.
Definition qoflog.h:256
#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 ENTER(format, args...)
Print a function entry debugging message.
Definition qoflog.h:272
void gnc_plugin_page_register_clear_current_filter(GncPluginPage *plugin_page)
This function clears the registers current filter.
GncPluginPage * gnc_plugin_page_register_new(Account *account, gboolean subaccounts)
Create a new "register" plugin page, given a pointer to an account.
GNCSplitReg * gnc_plugin_page_register_get_gsr(GncPluginPage *plugin_page)
Get the GNCSplitReg data structure associated with this register page.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
gchar * gnc_uri_get_path(const gchar *uri)
Extracts the path part from a uri.
gchar * gnc_uri_get_scheme(const gchar *uri)
Extracts the scheme from a uri.
gboolean gnc_uri_is_file_scheme(const gchar *scheme)
Checks if the given scheme is used to refer to a file (as opposed to a network service like a databas...
STRUCTS.
The instance data structure for a content plugin.
QofBook reference.
Definition qofbook-p.hpp:47