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.
This commit is contained in:
Robert Fewell 2020-05-18 15:50:26 +01:00
parent 7e05d8690a
commit 07d46d5d52
7 changed files with 700 additions and 25 deletions

View File

@ -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

View File

@ -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 <config.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#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);
}

View File

@ -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

View File

@ -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);

View File

@ -265,6 +265,204 @@
<action-widget response="-5">ok_button</action-widget>
</action-widgets>
</object>
<object class="GtkDialog" id="association_path_head_changed_dialog">
<property name="can_focus">False</property>
<property name="default_width">450</property>
<property name="type_hint">dialog</property>
<child>
<placeholder/>
</child>
<child internal-child="vbox">
<object class="GtkBox">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="button4">
<property name="label" translatable="yes">_OK</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Change Association path head</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="existing_path_head">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">6</property>
<style>
<class name="gnc-class-highlight"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="existing_path_hbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">12</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Existing relative file path associations will be converted to absolute ones by combining them with the existing path head unless box unticked.</property>
<property name="wrap">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="use_old_path_head">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="halign">start</property>
<property name="valign">end</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="new_path_head">
<property name="visible">True</property>
<property name="can_focus">False</property>
<style>
<class name="gnc-class-highlight"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkBox" id="new_path_hbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Existing absolute file path associations will be converted to relative ones by comparing them to the new path head unless box unticked.</property>
<property name="wrap">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="use_new_path_head">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="halign">start</property>
<property name="valign">end</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="margin_top">12</property>
<property name="label" translatable="yes">Note: Only Associations that are not read-only will be changed.</property>
<property name="wrap">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="-5">button4</action-widget>
</action-widgets>
</object>
<object class="GtkListStore" id="list-store">
<columns>
<!-- column-name date -->

View File

@ -1698,7 +1698,7 @@ many months before the current month</property>
<object class="GtkBox" id="pref/general/assoc-head">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_markup" translatable="yes">Path head for Transaction Associated files </property>
<property name="tooltip_markup" translatable="yes">Path head for Associated files</property>
<child>
<placeholder/>
</child>
@ -1716,7 +1716,7 @@ many months before the current month</property>
<object class="GtkLabel" id="label20">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Path head for Transaction Association Files</property>
<property name="label" translatable="yes">Path head for Associated Files</property>
<property name="use_markup">True</property>
</object>
<packing>
@ -1782,7 +1782,7 @@ many months before the current month</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">&lt;b&gt;Transaction Association&lt;/b&gt;</property>
<property name="label" translatable="yes">&lt;b&gt;Associated Files&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
<packing>

View File

@ -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