From 07d46d5d529ad5b1102e23356aa7aa75ec548f9c Mon Sep 17 00:00:00 2001 From: Robert Fewell <14uBobIT@gmail.com> Date: Mon, 18 May 2020 15:50:26 +0100 Subject: [PATCH] Add option to change associations when path head changes When the path head is changed the associations are not updated so this change adds a dialog to ask if you want the old relative paths updated to absolute ones and whether to update existing absolute paths to new relative ones. --- gnucash/gnome-utils/CMakeLists.txt | 2 + gnucash/gnome-utils/dialog-assoc-utils.c | 390 ++++++++++++++++++++ gnucash/gnome-utils/dialog-assoc-utils.h | 67 ++++ gnucash/gnome-utils/dialog-preferences.c | 61 +-- gnucash/gtkbuilder/dialog-assoc.glade | 198 ++++++++++ gnucash/gtkbuilder/dialog-preferences.glade | 6 +- po/POTFILES.in | 1 + 7 files changed, 700 insertions(+), 25 deletions(-) create mode 100644 gnucash/gnome-utils/dialog-assoc-utils.c create mode 100644 gnucash/gnome-utils/dialog-assoc-utils.h diff --git a/gnucash/gnome-utils/CMakeLists.txt b/gnucash/gnome-utils/CMakeLists.txt index 6748b002e4..098c88d17f 100644 --- a/gnucash/gnome-utils/CMakeLists.txt +++ b/gnucash/gnome-utils/CMakeLists.txt @@ -30,6 +30,7 @@ set (gnome_utils_SOURCES assistant-xml-encoding.c cursors.c dialog-account.c + dialog-assoc-utils.c dialog-book-close.c dialog-commodity.c dialog-dup-trans.c @@ -123,6 +124,7 @@ set (gnome_utils_HEADERS account-quickfill.h assistant-xml-encoding.h dialog-account.h + dialog-assoc-utils.h dialog-book-close.h dialog-commodity.h dialog-dup-trans.h diff --git a/gnucash/gnome-utils/dialog-assoc-utils.c b/gnucash/gnome-utils/dialog-assoc-utils.c new file mode 100644 index 0000000000..30e1b38472 --- /dev/null +++ b/gnucash/gnome-utils/dialog-assoc-utils.c @@ -0,0 +1,390 @@ +/********************************************************************\ + * dialog-assoc-utils.c -- Associations dialog Utils * + * Copyright (C) 2020 Robert Fewell * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License* + * along with this program; if not, contact: * + * * + * Free Software Foundation Voice: +1-617-542-5942 * + * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * + * Boston, MA 02110-1301, USA gnu@gnu.org * +\********************************************************************/ + +#include + +#include +#include + +#include "dialog-assoc-utils.h" + +#include "dialog-utils.h" +#include "Transaction.h" + +#include "gnc-prefs.h" +#include "gnc-ui.h" +#include "gnc-ui-util.h" +#include "gnc-gnome-utils.h" +#include "gnc-uri-utils.h" +#include "gnc-filepath-utils.h" +#include "Account.h" + +/* This static indicates the debugging module that this .o belongs to. */ +static QofLogModule log_module = GNC_MOD_GUI; + +/***********************************************************************/ + +static gchar * +convert_uri_to_abs_path (const gchar *path_head, const gchar *uri, gchar *uri_scheme, gboolean return_uri) +{ + gchar *ret_value = NULL; + + if (!uri_scheme) // relative path + { + gchar *path = gnc_uri_get_path (path_head); + gchar *file_path = gnc_file_path_absolute (path, uri); + + if (return_uri) + ret_value = gnc_uri_create_uri ("file", NULL, 0, NULL, NULL, file_path); + else + ret_value = g_strdup (file_path); + + g_free (path); + g_free (file_path); + } + + if (g_strcmp0 (uri_scheme, "file") == 0) // absolute path + { + if (return_uri) + ret_value = g_strdup (uri); + else + ret_value = gnc_uri_get_path (uri); + } + return ret_value; +} + +gchar * +gnc_assoc_get_unescape_uri (const gchar *path_head, const gchar *uri, gchar *uri_scheme) +{ + gchar *display_str = NULL; + + if (uri && *uri) + { + // if scheme is null or 'file' we should get a file path + gchar *file_path = convert_uri_to_abs_path (path_head, uri, uri_scheme, FALSE); + + if (file_path) + display_str = g_uri_unescape_string (file_path, NULL); + else + display_str = g_uri_unescape_string (uri, NULL); + + g_free (file_path); + +#ifdef G_OS_WIN32 // make path look like a traditional windows path + display_str = g_strdelimit (display_str, "/", '\\'); +#endif + } + DEBUG("Return display string is '%s'", display_str); + return display_str; +} + +static gchar * +gnc_assoc_get_use_uri (const gchar *path_head, const gchar *uri, gchar *uri_scheme) +{ + gchar *use_str = NULL; + + if (uri && *uri) + { + // if scheme is null or 'file' we should get a file path + gchar *file_path = convert_uri_to_abs_path (path_head, uri, uri_scheme, TRUE); + + if (file_path) + use_str = g_strdup (file_path); + else + use_str = g_strdup (uri); + + g_free (file_path); + } + DEBUG("Return use string is '%s'", use_str); + return use_str; +} + +static gchar* +gnc_assoc_convert_trans_associate_uri (gpointer trans, gboolean book_ro) +{ + const gchar *uri = xaccTransGetAssociation (trans); // get the existing uri + const gchar *part = NULL; + + if (!uri) + return NULL; + + if (g_str_has_prefix (uri, "file:") && !g_str_has_prefix (uri,"file://")) + { + /* fix an earlier error when storing relative paths before version 3.5 + * they were stored starting as 'file:' or 'file:/' depending on OS + * relative paths are stored without a leading "/" and in native form + */ + if (g_str_has_prefix (uri,"file:/")) + part = uri + strlen ("file:/"); + else if (g_str_has_prefix (uri,"file:")) + part = uri + strlen ("file:"); + + if (!xaccTransGetReadOnly (trans) && !book_ro) + xaccTransSetAssociation (trans, part); + + return g_strdup (part); + } + return g_strdup (uri); +} + +/***********************************************************************/ + +static gchar * +assoc_get_path_head_and_set (gboolean *path_head_set) +{ + gchar *ret_path = NULL; + gchar *path_head = gnc_prefs_get_string (GNC_PREFS_GROUP_GENERAL, "assoc-head"); + *path_head_set = FALSE; + + if (path_head && *path_head) // not default entry + { + *path_head_set = TRUE; + ret_path = g_strdup (path_head); + } + else + { + const gchar *doc = g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS); + + if (doc) + ret_path = gnc_uri_create_uri ("file", NULL, 0, NULL, NULL, doc); + else + ret_path = gnc_uri_create_uri ("file", NULL, 0, NULL, NULL, gnc_userdata_dir ()); + } + // make sure there is a trailing '/' + if (!g_str_has_suffix (ret_path, "/")) + { + gchar *folder_with_slash = g_strconcat (ret_path, "/", NULL); + g_free (ret_path); + ret_path = g_strdup (folder_with_slash); + g_free (folder_with_slash); + + if (*path_head_set) // prior to 3.5, assoc-head could be with or without a trailing '/' + { + if (!gnc_prefs_set_string (GNC_PREFS_GROUP_GENERAL, "assoc-head", ret_path)) + PINFO ("Failed to save preference at %s, %s with %s", + GNC_PREFS_GROUP_GENERAL, "assoc-head", ret_path); + } + } + g_free (path_head); + return ret_path; +} + +gchar * +gnc_assoc_get_path_head (void) +{ + gboolean path_head_set = FALSE; + + return assoc_get_path_head_and_set (&path_head_set); +} + +static void +gnc_assoc_set_path_head_label (GtkWidget *path_head_label, const gchar *incoming_path_head, const gchar *prefix) +{ + gboolean path_head_set = FALSE; + gchar *path_head = NULL; + gchar *scheme; + gchar *path_head_str; + gchar *path_head_text; + + if (incoming_path_head) + { + path_head = g_strdup (incoming_path_head); + path_head_set = TRUE; + } + else + path_head = assoc_get_path_head_and_set (&path_head_set); + + scheme = gnc_uri_get_scheme (path_head); + path_head_str = gnc_assoc_get_unescape_uri (NULL, path_head, scheme); + + if (path_head_set) + { + // test for current folder being present + if (g_file_test (path_head_str, G_FILE_TEST_IS_DIR)) + path_head_text = g_strdup_printf ("%s '%s'", _("Path head for files is,"), path_head_str); + else + path_head_text = g_strdup_printf ("%s '%s'", _("Path head does not exist,"), path_head_str); + } + else + path_head_text = g_strdup_printf (_("Path head not set, using '%s' for relative paths"), path_head_str); + + if (prefix) + { + gchar *tmp = g_strdup (path_head_text); + g_free (path_head_text); + + path_head_text = g_strdup_printf ("%s %s", prefix, tmp); + + g_free (tmp); + } + + gtk_label_set_text (GTK_LABEL(path_head_label), path_head_text); + + // Set the style context for this label so it can be easily manipulated with css + gnc_widget_style_context_add_class (GTK_WIDGET(path_head_label), "gnc-class-highlight"); + + g_free (scheme); + g_free (path_head_str); + g_free (path_head_text); + g_free (path_head); +} + +/***********************************************************************/ + +typedef struct +{ + const gchar *old_path_head_uri; + gboolean change_old; + const gchar *new_path_head_uri; + gboolean change_new; + gboolean book_ro; +}AssocUpdate; + +static void +update_trans_uri (QofInstance* data, gpointer user_data) +{ + AssocUpdate *assoc_update = user_data; + Transaction *trans = GNC_TRANSACTION(data); + gchar *uri; + + // fix an earlier error when storing relative paths before version 3.5 + uri = gnc_assoc_convert_trans_associate_uri (trans, assoc_update->book_ro); + + if (uri && *uri) + { + gboolean rel = FALSE; + gchar *scheme = gnc_uri_get_scheme (uri); + + if (!scheme) // path is relative + rel = TRUE; + + // check for relative and we want to change them + if (rel && assoc_update->change_old) + { + gchar *new_uri = gnc_assoc_get_use_uri (assoc_update->old_path_head_uri, uri, scheme); + + if (!xaccTransGetReadOnly (trans)) + xaccTransSetAssociation (trans, new_uri); + + g_free (new_uri); + } + g_free (scheme); + + // check for not relative and we want to change them + if (!rel && assoc_update->change_new && g_str_has_prefix (uri, assoc_update->new_path_head_uri)) + { + // relative paths do not start with a '/' + const gchar *part = uri + strlen (assoc_update->new_path_head_uri); + gchar *new_uri = g_strdup (part); + + if (!xaccTransGetReadOnly (trans)) + xaccTransSetAssociation (trans, new_uri); + + g_free (new_uri); + } + } + g_free (uri); +} + +static void +change_relative_and_absolute_uri_paths (const gchar *old_path_head_uri, gboolean change_old, + const gchar *new_path_head_uri, gboolean change_new) +{ + QofBook *book = gnc_get_current_book(); + gboolean book_ro = qof_book_is_readonly (book); + AssocUpdate *assoc_update; + + /* if book is read only, nothing to do */ + if (book_ro) + return; + + assoc_update = g_new0 (AssocUpdate, 1); + + assoc_update->old_path_head_uri = old_path_head_uri; + assoc_update->new_path_head_uri = new_path_head_uri; + assoc_update->change_old = change_old; + assoc_update->change_new = change_new; + assoc_update->book_ro = book_ro; + + /* Loop through the transactions */ + qof_collection_foreach (qof_book_get_collection (book, GNC_ID_TRANS), + update_trans_uri, assoc_update); + + g_free (assoc_update); +} + +void +gnc_assoc_pref_path_head_changed (GtkWindow *parent, const gchar *old_path_head_uri) +{ + GtkWidget *dialog; + GtkBuilder *builder; + GtkWidget *use_old_path_head, *use_new_path_head; + GtkWidget *old_head_label, *new_head_label; + GtkWidget *old_hbox, *new_hbox; + gint result; + gchar *new_path_head_uri = gnc_assoc_get_path_head (); + + if (g_strcmp0 (old_path_head_uri, new_path_head_uri) == 0) + { + g_free (new_path_head_uri); + return; + } + + /* Create the dialog box */ + builder = gtk_builder_new(); + gnc_builder_add_from_file (builder, "dialog-assoc.glade", "association_path_head_changed_dialog"); + dialog = GTK_WIDGET(gtk_builder_get_object (builder, "association_path_head_changed_dialog")); + + if (parent != NULL) + gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(parent)); + + // Set the name and style context for this widget so it can be easily manipulated with css + gtk_widget_set_name (GTK_WIDGET(dialog), "gnc-id-association-change"); + gnc_widget_style_context_add_class (GTK_WIDGET(dialog), "gnc-class-association"); + + old_head_label = GTK_WIDGET(gtk_builder_get_object (builder, "existing_path_head")); + new_head_label = GTK_WIDGET(gtk_builder_get_object (builder, "new_path_head")); + + use_old_path_head = GTK_WIDGET(gtk_builder_get_object (builder, "use_old_path_head")); + use_new_path_head = GTK_WIDGET(gtk_builder_get_object (builder, "use_new_path_head")); + + // display path head text and test if present + gnc_assoc_set_path_head_label (old_head_label, old_path_head_uri, _("Exsiting")); + gnc_assoc_set_path_head_label (new_head_label, new_path_head_uri, _("New")); + + gtk_widget_show (dialog); + g_object_unref (G_OBJECT(builder)); + + // run the dialog + result = gtk_dialog_run (GTK_DIALOG(dialog)); + if (result == GTK_RESPONSE_OK) + { + gboolean use_old = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(use_old_path_head)); + gboolean use_new = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(use_new_path_head)); + + if (use_old || use_new) + change_relative_and_absolute_uri_paths (old_path_head_uri, use_old, + new_path_head_uri, use_new); + } + g_free (new_path_head_uri); + gtk_widget_destroy (dialog); +} diff --git a/gnucash/gnome-utils/dialog-assoc-utils.h b/gnucash/gnome-utils/dialog-assoc-utils.h new file mode 100644 index 0000000000..6d181b64f4 --- /dev/null +++ b/gnucash/gnome-utils/dialog-assoc-utils.h @@ -0,0 +1,67 @@ +/********************************************************************\ + * dialog-assoc-utils.h -- Associations dialog Utils * + * Copyright (C) 2020 Robert Fewell * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License* + * along with this program; if not, contact: * + * * + * Free Software Foundation Voice: +1-617-542-5942 * + * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * + * Boston, MA 02110-1301, USA gnu@gnu.org * +\********************************************************************/ + +#ifndef DIALOG_ASSOC_UTILS_H +#define DIALOG_ASSOC_UTILS_H + +/** Return the current associate path head uri. + * + * This function will get the current associate path head from pref's. + * If it is not set then a default path head is set based on either + * the home directory or the user data directory. + * + * The calling function should free the returned value with g_free when + * the it is no longer needed. + * + * @return The current associate path head. + */ +gchar * gnc_assoc_get_path_head (void); + +/** Return an unescaped uri for display use. + * + * The function allocates memory for the uri. The calling function should + * free this memory with g_free when the unescaped uri is no longer needed. + + * Return an unesacped uri for displaying and if OS is windows change the + * '/' to '\' to look like a traditional windows path + * + * @param path_head The starting common path head + * @param uri The association + * @param uri_scheme + * + * @return The unescaped uri used for display purposes. + */ +gchar * gnc_assoc_get_unescape_uri (const gchar *path_head, const gchar *uri, gchar *uri_scheme); + +/** Presents a dialog when the path head is changed. + * + * When the path head is changed a dialog is raised that allows for + * existing relative file associations to be made absolute based on the + * old_path_head_uri and existing absolute file associations to be made + * relative based on the new_path_head_uri. + * + * @param parent The GtkWindow for the parent widget + * @param old_path_head_uri The old path head uri + */ +void gnc_assoc_pref_path_head_changed (GtkWindow *parent, const gchar *old_path_head_uri); + +#endif diff --git a/gnucash/gnome-utils/dialog-preferences.c b/gnucash/gnome-utils/dialog-preferences.c index 44e2015a2e..137bf0bfe5 100644 --- a/gnucash/gnome-utils/dialog-preferences.c +++ b/gnucash/gnome-utils/dialog-preferences.c @@ -77,6 +77,7 @@ #include "gnc-ui-util.h" #include "gnc-component-manager.h" #include "dialog-preferences.h" +#include "dialog-assoc-utils.h" #define DIALOG_PREFERENCES_CM_CLASS "dialog-newpreferences" #define GNC_PREFS_GROUP "dialogs.preferences" @@ -749,24 +750,29 @@ file_chooser_selected_cb (GtkFileChooser *fc, gpointer user_data) { GtkImage *image = g_object_get_data (G_OBJECT(fc), "path_head_error"); const gchar *group = g_object_get_data (G_OBJECT(fc), "group"); - const gchar *pref = g_object_get_data (G_OBJECT(fc), "pref"); - gchar *folder = gtk_file_chooser_get_uri (fc); + const gchar *pref = g_object_get_data (G_OBJECT(fc), "pref"); + gchar *folder_uri = gtk_file_chooser_get_uri (fc); + gchar *old_path_head_uri = gnc_assoc_get_path_head (); // make sure path_head ends with a trailing '/', 3.5 onwards - if (!g_str_has_suffix (folder, "/")) + if (!g_str_has_suffix (folder_uri, "/")) { - gchar *folder_with_slash = g_strconcat (folder, "/", NULL); - g_free (folder); - folder = g_strdup (folder_with_slash); + gchar *folder_with_slash = g_strconcat (folder_uri, "/", NULL); + g_free (folder_uri); + folder_uri = g_strdup (folder_with_slash); g_free (folder_with_slash); } gtk_widget_hide (GTK_WIDGET(image)); - if (!gnc_prefs_set_string (group, pref, folder)) - PINFO("Failed to save preference at %s, %s with %s", group, pref, folder); - - g_free (folder); + if (!gnc_prefs_set_string (group, pref, folder_uri)) + PINFO("Failed to save preference at %s, %s with %s", group, pref, folder_uri); + else + gnc_assoc_pref_path_head_changed (GTK_WINDOW(gtk_widget_get_toplevel ( + GTK_WIDGET(fc))), old_path_head_uri); + + g_free (old_path_head_uri); + g_free (folder_uri); } /** Connect a GtkFileChooserButton widget to its stored value in the preferences database. @@ -785,10 +791,10 @@ gnc_prefs_connect_file_chooser_button (GtkFileChooserButton *fcb, const gchar *b gchar *uri; gboolean folder_set = TRUE; - g_return_if_fail(GTK_FILE_CHOOSER_BUTTON(fcb)); + g_return_if_fail (GTK_FILE_CHOOSER_BUTTON(fcb)); if (boxname == NULL) - gnc_prefs_split_widget_name (gtk_buildable_get_name(GTK_BUILDABLE(fcb)), &group, &pref); + gnc_prefs_split_widget_name (gtk_buildable_get_name (GTK_BUILDABLE(fcb)), &group, &pref); else gnc_prefs_split_widget_name (boxname, &group, &pref); @@ -796,7 +802,7 @@ gnc_prefs_connect_file_chooser_button (GtkFileChooserButton *fcb, const gchar *b PINFO("Uri is %s", uri); - if (uri && *uri != '\0') // default entry + if (uri && *uri) // default entry { gchar *path_head = g_filename_from_uri (uri, NULL, NULL); @@ -809,21 +815,19 @@ gnc_prefs_connect_file_chooser_button (GtkFileChooserButton *fcb, const gchar *b g_free (path_head); } - image = g_object_get_data(G_OBJECT(fcb), "path_head_error"); + image = g_object_get_data (G_OBJECT(fcb), "path_head_error"); if (folder_set) // If current folder missing, display error and tt message gtk_widget_hide (GTK_WIDGET(image)); else { - gchar *uri_u = g_uri_unescape_string (uri, NULL); - gchar *path_head = g_filename_from_uri (uri_u, NULL, NULL); + gchar *path_head = gnc_assoc_get_unescape_uri (NULL, uri, "file"); gchar *ttip = g_strconcat (_("Path does not exist, "), path_head, NULL); - gtk_widget_set_tooltip_text(GTK_WIDGET(image), ttip); + gtk_widget_set_tooltip_text (GTK_WIDGET(image), ttip); gtk_widget_show (GTK_WIDGET(image)); g_free (ttip); - g_free (uri_u); g_free (path_head); } @@ -837,7 +841,7 @@ gnc_prefs_connect_file_chooser_button (GtkFileChooserButton *fcb, const gchar *b g_free (pref); g_free (uri); - gtk_widget_show_all(GTK_WIDGET(fcb)); + gtk_widget_show_all (GTK_WIDGET(fcb)); } /** Callback for a 'Clear' button for GtkFileChooserButton widget. @@ -858,28 +862,40 @@ file_chooser_clear_cb (GtkButton *button, gpointer user_data) GtkWidget *box; GtkWidget *fcb_new; gchar *boxname; + gchar *old_path_head_uri = gnc_assoc_get_path_head (); /* We need to destroy the GtkFileChooserButton and recreate as there does not seem to be away of resetting the folder path to NONE */ box = gtk_widget_get_parent (GTK_WIDGET(fcb)); - gtk_widget_destroy (GTK_WIDGET(fcb)); + g_signal_handlers_disconnect_by_func (button, file_chooser_clear_cb, fcb); if (!gnc_prefs_set_string (group, pref, "")) PINFO("Failed to Clear preference at %s, %s", group, pref); + else + gnc_assoc_pref_path_head_changed (GTK_WINDOW(gtk_widget_get_toplevel ( + GTK_WIDGET(fcb))), old_path_head_uri); + + gtk_widget_destroy (GTK_WIDGET(fcb)); fcb_new = gtk_file_chooser_button_new (_("Select a folder"), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER); g_object_set_data (G_OBJECT(fcb_new), "path_head_error", image); + g_object_set_data_full (G_OBJECT(fcb_new),"group", g_strdup (group), (GDestroyNotify) g_free); + g_object_set_data_full (G_OBJECT(fcb_new),"pref", g_strdup (pref), (GDestroyNotify) g_free); - gtk_box_pack_start (GTK_BOX (box), fcb_new, TRUE, TRUE, 0); - gtk_box_reorder_child (GTK_BOX (box),fcb_new, 0); + gtk_box_pack_start (GTK_BOX(box), fcb_new, TRUE, TRUE, 0); + gtk_box_reorder_child (GTK_BOX(box), fcb_new, 0); gtk_widget_show (fcb_new); + g_signal_connect (GTK_BUTTON(button), "clicked", + G_CALLBACK(file_chooser_clear_cb), fcb_new); + boxname = g_strconcat ("pref/", group, "/", pref, NULL); gnc_prefs_connect_file_chooser_button (GTK_FILE_CHOOSER_BUTTON(fcb_new), boxname); g_free (boxname); + g_free (old_path_head_uri); } /****************************************************************************/ @@ -1385,6 +1401,7 @@ gnc_preferences_dialog_create(GtkWindow *parent) if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path)) gtk_list_store_set (store, &iter, 1, buf, -1); g_date_free(gdate); + gtk_tree_path_free (path); locale_currency = gnc_locale_default_currency (); currency_name = gnc_commodity_get_printname(locale_currency); diff --git a/gnucash/gtkbuilder/dialog-assoc.glade b/gnucash/gtkbuilder/dialog-assoc.glade index 98b33e0acf..7bb747fd7f 100644 --- a/gnucash/gtkbuilder/dialog-assoc.glade +++ b/gnucash/gtkbuilder/dialog-assoc.glade @@ -265,6 +265,204 @@ ok_button + + False + 450 + dialog + + + + + + False + vertical + 2 + + + False + end + + + _OK + True + True + True + True + + + True + True + 1 + + + + + False + False + 0 + + + + + True + False + vertical + 6 + + + True + False + Change Association path head + + + + + + False + True + 0 + + + + + True + False + 6 + + + + False + True + 1 + + + + + True + False + 12 + + + True + False + start + Existing relative file path associations will be converted to absolute ones by combining them with the existing path head unless box unticked. + True + + + False + True + 0 + + + + + True + True + False + start + end + True + True + + + False + True + 1 + + + + + False + True + 2 + + + + + True + False + + + + False + True + 3 + + + + + True + False + + + True + False + start + Existing absolute file path associations will be converted to relative ones by comparing them to the new path head unless box unticked. + True + + + False + True + 0 + + + + + True + True + False + start + end + True + True + + + False + True + 1 + + + + + False + True + 4 + + + + + True + False + start + 12 + Note: Only Associations that are not read-only will be changed. + True + + + False + True + 5 + + + + + False + True + 1 + + + + + + button4 + + diff --git a/gnucash/gtkbuilder/dialog-preferences.glade b/gnucash/gtkbuilder/dialog-preferences.glade index ab70d7f276..e25b9a1408 100644 --- a/gnucash/gtkbuilder/dialog-preferences.glade +++ b/gnucash/gtkbuilder/dialog-preferences.glade @@ -1698,7 +1698,7 @@ many months before the current month True False - Path head for Transaction Associated files + Path head for Associated files @@ -1716,7 +1716,7 @@ many months before the current month True False - Path head for Transaction Association Files + Path head for Associated Files True @@ -1782,7 +1782,7 @@ many months before the current month True False start - <b>Transaction Association</b> + <b>Associated Files</b> True diff --git a/po/POTFILES.in b/po/POTFILES.in index 2306930f0e..881c4f03af 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -128,6 +128,7 @@ gnucash/gnome-utils/account-quickfill.c gnucash/gnome-utils/assistant-xml-encoding.c gnucash/gnome-utils/cursors.c gnucash/gnome-utils/dialog-account.c +gnucash/gnome-utils/dialog-assoc-utils.c gnucash/gnome-utils/dialog-book-close.c gnucash/gnome-utils/dialog-commodity.c gnucash/gnome-utils/dialog-dup-trans.c