GnuCash c935c2f+
Loading...
Searching...
No Matches
gnc-imp-settings-csv-tx.cpp
Go to the documentation of this file.
1/*******************************************************************\
2 * gnc-imp-settings-csv-tx.cpp -- Trans CSV Import Settings *
3 * *
4 * Copyright (C) 2014 Robert Fewell *
5 * *
6 * This program is free software; you can redistribute it and/or *
7 * modify it under the terms of the GNU General Public License as *
8 * published by the Free Software Foundation; either version 2 of *
9 * the License, or (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License*
17 * along with this program; if not, contact: *
18 * *
19 * Free Software Foundation Voice: +1-617-542-5942 *
20 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21 * Boston, MA 02110-1301, USA gnu@gnu.org *
22\********************************************************************/
31#include <algorithm>
32#include <memory>
33#include <sstream>
34#include <string>
35#include <vector>
36#include <cstdint>
37
38#include <config.h>
39
40#include <gtk/gtk.h>
41#include <glib/gi18n.h>
42
43#include "Account.h"
44#include "gnc-state.h"
45#include "gnc-ui-util.h"
46
47constexpr auto group_prefix = "Import csv,transaction - ";
48
49#define CSV_COL_TYPES "ColumnTypes"
50
51#define CSV_ACCOUNT "BaseAccount"
52#define CSV_ACCOUNT_GUID "BaseAccountGuid"
53#define CSV_MULTI_SPLIT "MultiSplit"
54
55G_GNUC_UNUSED static QofLogModule log_module = GNC_MOD_IMPORT;
56
57preset_vec_trans presets_trans;
58
59static std::shared_ptr<CsvTransImpSettings> create_int_no_preset(void)
60{
61 auto preset = std::make_shared<CsvTransImpSettings>();
62 preset->m_name = get_no_settings();
63
64 return preset;
65}
66
67static std::shared_ptr<CsvTransImpSettings> create_int_gnc_exp_preset(void)
68{
69 auto preset = std::make_shared<CsvTransImpSettings>();
70 preset->m_name = get_gnc_exp();
71 preset->m_skip_start_lines = 1;
72 preset->m_multi_split = true;
73
74 /* FIXME date and currency format should still be aligned with export format!
75 * That's currently hard to do, because the export uses whatever the user
76 * had set as global preference.
77 preset->date_active = 0;
78 preset->currency_active = 0;
79 */
80 preset->m_column_types = {
81 GncTransPropType::DATE,
82 GncTransPropType::UNIQUE_ID,
83 GncTransPropType::NUM,
84 GncTransPropType::DESCRIPTION,
85 GncTransPropType::NOTES,
86 GncTransPropType::COMMODITY,
87 GncTransPropType::VOID_REASON,
88 GncTransPropType::ACTION,
89 GncTransPropType::MEMO,
90 GncTransPropType::ACCOUNT,
91 GncTransPropType::NONE,
92 GncTransPropType::NONE,
93 GncTransPropType::AMOUNT,
94 GncTransPropType::NONE,
95 GncTransPropType::VALUE,
96 GncTransPropType::REC_STATE,
97 GncTransPropType::REC_DATE,
98 GncTransPropType::PRICE
99 };
100 return preset;
101}
102
103static std::shared_ptr<CsvTransImpSettings> create_int_gnc_exp_4_preset(void)
104{
105 auto preset = std::make_shared<CsvTransImpSettings>();
106 preset->m_name = get_gnc_exp_4();
107 preset->m_skip_start_lines = 1;
108 preset->m_multi_split = true;
109
110 /* FIXME date and currency format should still be aligned with export format!
111 * That's currently hard to do, because the export uses whatever the user
112 * had set as global preference.
113 * preset->date_active = 0;
114 * preset->currency_active = 0;
115 */
116 preset->m_column_types = {
117 GncTransPropType::DATE,
118 GncTransPropType::UNIQUE_ID,
119 GncTransPropType::NUM,
120 GncTransPropType::DESCRIPTION,
121 GncTransPropType::NOTES,
122 GncTransPropType::COMMODITY,
123 GncTransPropType::VOID_REASON,
124 GncTransPropType::ACTION,
125 GncTransPropType::MEMO,
126 GncTransPropType::ACCOUNT,
127 GncTransPropType::NONE,
128 GncTransPropType::NONE,
129 GncTransPropType::AMOUNT,
130 GncTransPropType::REC_STATE,
131 GncTransPropType::REC_DATE,
132 GncTransPropType::PRICE
133 };
134 return preset;
135}
136
137/**************************************************
138 * find
139 *
140 * find all settings entries in the state key file
141 * based on settings type.
142 **************************************************/
143const preset_vec_trans& get_import_presets_trans (void)
144{
145 // Search all Groups in the state key file for ones starting with prefix
146 auto preset_names = std::vector<std::string>();
147 auto keyfile = gnc_state_get_current ();
148 gsize grouplength;
149 gchar **groups = g_key_file_get_groups (keyfile, &grouplength);
150
151 /* Start by building a sorted list of candidate presets as found in the state file */
152 for (gsize i=0; i < grouplength; i++)
153 {
154 auto group = std::string(groups[i]);
155 auto gp = std::string {group_prefix};
156 auto pos = group.find(gp);
157 if (pos == std::string::npos)
158 continue;
159
160 preset_names.push_back(group.substr(gp.size()));
161 }
162 // string array from the state file is no longer needed now.
163 g_strfreev (groups);
164
165 /* We want our settings to appear sorted alphabetically to the user */
166 std::sort(preset_names.begin(), preset_names.end());
167
168 /* Now add each preset to our global list */
169 presets_trans.clear();
170
171 /* Start with the internally generated ones */
172 presets_trans.push_back(create_int_no_preset());
173 presets_trans.push_back(create_int_gnc_exp_preset());
174 presets_trans.push_back(create_int_gnc_exp_4_preset());
175
176 /* Then add all the ones we found in the state file */
177 for (auto preset_name : preset_names)
178 {
179 auto preset = std::make_shared<CsvTransImpSettings>();
180 preset->m_name = preset_name;
181 preset->load();
182 presets_trans.push_back(preset);
183 }
184 return presets_trans;
185}
186
187/**************************************************
188 * load
189 *
190 * load the settings from a state key file
191 **************************************************/
192bool
194{
195 if (preset_is_reserved_name (m_name))
196 return true;
197
198 GError *key_error = nullptr;
199 m_load_error = false;
200 auto keyfile = gnc_state_get_current ();
201 auto group = get_group_prefix() + m_name;
202
203 // Start Loading the settings
204 m_load_error = CsvImportSettings::load(); // load the common settings
205
206 m_multi_split = g_key_file_get_boolean (keyfile, group.c_str(), CSV_MULTI_SPLIT, &key_error);
207 m_load_error |= handle_load_error (&key_error, group);
208
209 gchar *key_char = g_key_file_get_string (keyfile, group.c_str(), CSV_ACCOUNT_GUID, &key_error);
210 if (key_char && *key_char != '\0')
211 {
212 QofBook* book = gnc_get_current_book ();
213 GncGUID guid;
214
215 if (string_to_guid (key_char, &guid)) // find account by guid first
216 m_base_account = xaccAccountLookup (&guid, book);
217 }
218 m_load_error |= handle_load_error (&key_error, group);
219 if (key_char)
220 g_free (key_char);
221
222 key_char = g_key_file_get_string (keyfile, group.c_str(), CSV_ACCOUNT, &key_error);
223 if (key_char && *key_char != '\0')
224 {
225 if (m_base_account == nullptr)
226 {
227 m_base_account = gnc_account_lookup_by_full_name (gnc_get_current_root_account(), key_char);
228
229 if (m_base_account) // save the account as guid, introduced in version 4.5
230 {
231 gchar acct_guid[GUID_ENCODING_LENGTH + 1];
232 guid_to_string_buff (xaccAccountGetGUID (m_base_account), acct_guid);
233 g_key_file_set_string (keyfile, group.c_str(), CSV_ACCOUNT_GUID, acct_guid);
234 }
235 }
236 else // check to see if saved full name is the same and save if not
237 {
238 gchar *full_name = gnc_account_get_full_name (m_base_account);
239
240 if (g_strcmp0 (key_char, full_name) != 0)
241 g_key_file_set_string (keyfile, group.c_str(), CSV_ACCOUNT, full_name);
242 g_free (full_name);
243 }
244 }
245 m_load_error |= handle_load_error (&key_error, group);
246 if (key_char)
247 g_free (key_char);
248
249 gsize list_len;
250 m_column_types.clear();
251 gchar** col_types_str = g_key_file_get_string_list (keyfile, group.c_str(), CSV_COL_TYPES,
252 &list_len, &key_error);
253 for (uint32_t i = 0; i < list_len; i++)
254 {
255 /* Special case a few legacy column names */
256 const char *col_type_str = col_types_str[i];
257 if (!g_strcmp0(col_type_str, "Deposit")) // -> "Amount"
258 col_type_str = gnc_csv_col_type_strs[GncTransPropType::AMOUNT];
259 if (!g_strcmp0(col_type_str, "Withdrawal")) // -> "Amount (Negated)"
260 col_type_str = gnc_csv_col_type_strs[GncTransPropType::AMOUNT_NEG];
261 if (!g_strcmp0(col_type_str, "Num")) // -> "Number"
262 col_type_str = gnc_csv_col_type_strs[GncTransPropType::NUM];
263 auto col_types_it = std::find_if (gnc_csv_col_type_strs.begin(),
264 gnc_csv_col_type_strs.end(), test_prop_type_str (col_type_str));
265 auto prop = GncTransPropType::NONE;
266 if (col_types_it != gnc_csv_col_type_strs.end())
267 {
268 /* Found a valid column type. Now check whether it is allowed
269 * in the selected mode (two-split vs multi-split) */
270 prop = sanitize_trans_prop (col_types_it->first, m_multi_split);
271 if (prop != col_types_it->first)
272 PWARN("Found column type '%s', but this is blacklisted when multi-split mode is %s. "
273 "Inserting column type 'NONE' instead'.",
274 col_types_it->second, m_multi_split ? "enabled" : "disabled");
275 }
276 else
277 PWARN("Found invalid column type '%s'. Inserting column type 'NONE' instead'.",
278 col_types_str[i]);
279 m_column_types.push_back(prop);
280 }
281 if (col_types_str)
282 g_strfreev (col_types_str);
283
284 return m_load_error;
285}
286
287/**************************************************
288 * save
289 *
290 * save settings to a key file
291 **************************************************/
292bool
294{
295 if (preset_is_reserved_name (m_name))
296 {
297 PWARN ("Ignoring attempt to save to reserved name '%s'", m_name.c_str());
298 return true;
299 }
300
301 if ((m_name.find('[') != std::string::npos))
302 {
303 PWARN ("Name '%s' contains invalid characters '[]'. Refusing to save", m_name.c_str());
304 return true;
305 }
306
307 auto keyfile = gnc_state_get_current ();
308 auto group = get_group_prefix() + m_name;
309
310 // Drop previous saved settings with this name
311 g_key_file_remove_group (keyfile, group.c_str(), nullptr);
312
313 // Start Saving the settings
314 bool error = CsvImportSettings::save(); // save the common settings
315
316 if (error)
317 return error;
318
319 g_key_file_set_boolean (keyfile, group.c_str(), CSV_MULTI_SPLIT, m_multi_split);
320
321 if (m_base_account) // also save account guid introduced in version 4.5
322 {
323 gchar acct_guid[GUID_ENCODING_LENGTH + 1];
324 guid_to_string_buff (xaccAccountGetGUID (m_base_account), acct_guid);
325 g_key_file_set_string (keyfile, group.c_str(), CSV_ACCOUNT_GUID, acct_guid);
326
327 gchar *full_name = gnc_account_get_full_name (m_base_account);
328 g_key_file_set_string (keyfile, group.c_str(), CSV_ACCOUNT, full_name);
329 g_free (full_name);
330 }
331
332 std::vector<const char*> col_types_str;
333 for (auto col_type : m_column_types)
334 col_types_str.push_back(gnc_csv_col_type_strs[col_type]);
335
336 if (!col_types_str.empty())
337 g_key_file_set_string_list (keyfile, group.c_str(), CSV_COL_TYPES,
338 col_types_str.data(), col_types_str.size());
339
340 return error;
341}
342
343void
345{
346 if (preset_is_reserved_name (m_name))
347 return;
348
350}
351
352const char*
353CsvTransImpSettings::get_group_prefix (void)
354{
355 return group_prefix;
356}
Account handling public routines.
const preset_vec_trans & get_import_presets_trans(void)
Creates a vector of CsvTransImpSettings which combines.
CSV Import Settings.
bool preset_is_reserved_name(const std::string &name)
Check whether name can be used as a preset name.
CSV Import Settings.
Functions to load, save and get gui state.
utility functions for the GnuCash UI
gchar * gnc_account_get_full_name(const Account *account)
The gnc_account_get_full_name routine returns the fully qualified name of the account using the given...
Definition Account.cpp:3305
#define xaccAccountGetGUID(X)
Definition Account.h:252
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id,...
Definition Account.cpp:2050
Account * gnc_account_lookup_by_full_name(const Account *any_acc, const gchar *name)
The gnc_account_lookup_full_name() subroutine works like gnc_account_lookup_by_name,...
Definition Account.cpp:3163
#define GUID_ENCODING_LENGTH
Number of characters needed to encode a guid as a string not including the null terminator.
Definition guid.h:84
gchar * guid_to_string_buff(const GncGUID *guid, gchar *str)
The guid_to_string_buff() routine puts a null-terminated string encoding of the id into the memory po...
Definition guid.cpp:208
GKeyFile * gnc_state_get_current(void)
Returns a pointer to the most recently loaded state.
Definition gnc-state.c:248
#define PWARN(format, args...)
Log a warning.
Definition qoflog.h:250
bool save(void)
Save the gathered widget properties to a key File.
bool load(void)
Load the widget properties from a key File.
void remove(void)
Remove the preset from the state file.
bool save(void)
Save the gathered widget properties to a key File.
void remove(void)
Remove the preset from the state file.
bool load(void)
Load the widget properties from a key File.
The type used to store guids in C.
Definition guid.h:75
QofBook reference.
Definition qofbook-p.hpp:47
Functor to check if the above map has an element of which the value equals name.