GnuCash  5.6-150-g038405b370+
gnc-imp-settings-csv.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2  * gnc-imp-settings-csv.cpp -- Save and Load 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 \********************************************************************/
29 #include "gnc-imp-settings-csv.hpp"
30 #include <sstream>
31 
32 #include <config.h>
33 
34 #include <gtk/gtk.h>
35 #include <glib/gi18n.h>
36 
37 #include "Account.h"
38 #include "gnc-state.h"
39 #include "gnc-ui-util.h"
40 
41 #include <algorithm>
42 #include <iostream>
43 #include <string>
44 
45 const std::string csv_group_prefix{"CSV-"};
46 const std::string no_settings{N_("No Settings")};
47 const std::string gnc_exp{N_("GnuCash Export Format")};
48 const std::string gnc_exp_4{N_("GnuCash Export Format (4.x and older)")};
49 
50 #define CSV_NAME "Name"
51 #define CSV_FORMAT "CsvFormat"
52 #define CSV_SKIP_ALT "SkipAltLines"
53 #define CSV_SKIP_START "SkipStartLines"
54 #define CSV_SKIP_END "SkipEndLines"
55 
56 #define CSV_SEP "Separators"
57 #define CSV_ESC "EnableEscape"
58 
59 #define CSV_CUSTOM "Custom"
60 #define CSV_CUSTOM_ENTRY "CustomEntry"
61 
62 #define CSV_DATE "DateFormat"
63 #define CSV_CURRENCY "CurrencyFormat"
64 
65 #define CSV_ENCODING "Encoding"
66 #define CSV_COL_WIDTHS "ColumnWidths"
67 
68 G_GNUC_UNUSED static QofLogModule log_module = GNC_MOD_IMPORT;
69 
70 /**************************************************
71  * handle_load_error
72  *
73  * record possible errors in the log file
74  * ignore key-not-found errors though. We'll just
75  * use a default value and go on.
76  **************************************************/
77 bool
78 handle_load_error (GError **key_error, const std::string& group)
79 {
80  if (!*key_error)
81  return false;
82 
83  if ((*key_error)->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND)
84  {
85  g_clear_error (key_error);
86  return false;
87  }
88 
89  g_warning ("Error reading group '%s' : %s", group.c_str(), (*key_error)->message);
90  g_clear_error (key_error);
91  return true;
92 }
93 
94 bool preset_is_reserved_name (const std::string& name)
95 {
96  return ((name == no_settings) ||
97  (name == _(no_settings.c_str())) ||
98  (name == gnc_exp) ||
99  (name == _(gnc_exp.c_str())));
100 }
101 
102 std::string get_no_settings (void)
103 {
104  return no_settings;
105 }
106 
107 std::string get_gnc_exp (void)
108 {
109  return gnc_exp;
110 }
111 
112 std::string get_gnc_exp_4 (void)
113 {
114  return gnc_exp_4;
115 }
116 
117 /**************************************************
118  * load_common
119  *
120  * load the settings from a state key file
121  **************************************************/
122 bool
124 {
125  GError *key_error = nullptr;
126  m_load_error = false;
127  auto group = get_group_prefix() + m_name;
128  auto keyfile = gnc_state_get_current ();
129 
130  m_skip_start_lines = g_key_file_get_integer (keyfile, group.c_str(), CSV_SKIP_START, &key_error);
131  m_load_error |= handle_load_error (&key_error, group);
132 
133  m_skip_end_lines = g_key_file_get_integer (keyfile, group.c_str(), CSV_SKIP_END, &key_error);
134  m_load_error |= handle_load_error (&key_error, group);
135 
136  m_skip_alt_lines = g_key_file_get_boolean (keyfile, group.c_str(), CSV_SKIP_ALT, &key_error);
137  m_load_error |= handle_load_error (&key_error, group);
138 
139  auto csv_format = g_key_file_get_boolean (keyfile, group.c_str(), CSV_FORMAT, &key_error);
140  if (key_error) csv_format = true; // default to true, but above command will return false in case of error
141  m_load_error |= handle_load_error (&key_error, group);
142  if (csv_format)
143  m_file_format = GncImpFileFormat::CSV;
144  else
145  m_file_format = GncImpFileFormat::FIXED_WIDTH;
146 
147  gchar *key_char = g_key_file_get_string (keyfile, group.c_str(), CSV_SEP, &key_error);
148  if (key_char && *key_char != '\0')
149  m_separators = key_char;
150  m_load_error |= handle_load_error (&key_error, group);
151  if (key_char)
152  g_free (key_char);
153 
154  m_enable_escape = g_key_file_get_boolean (keyfile, group.c_str(), CSV_ESC, &key_error);
155  // Older import settings will not have a value for escape processing
156  // so set it to true if no value is found in the file format settings
157  if (key_error && key_error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND)
158  m_enable_escape = true;
159  else
160  m_load_error |= handle_load_error (&key_error, group);
161 
162  m_date_format = g_key_file_get_integer (keyfile, group.c_str(), CSV_DATE, &key_error);
163  m_load_error |= handle_load_error (&key_error, group);
164 
165  m_currency_format = g_key_file_get_integer (keyfile, group.c_str(), CSV_CURRENCY, &key_error);
166  m_load_error |= handle_load_error (&key_error, group);
167 
168  key_char = g_key_file_get_string (keyfile, group.c_str(), CSV_ENCODING, &key_error);
169  if (key_char && *key_char != '\0')
170  m_encoding = key_char;
171  else
172  m_encoding = "UTF-8";
173  m_load_error |= handle_load_error (&key_error, group);
174  if (key_char)
175  g_free (key_char);
176 
177  // Widths
178  gsize list_len;
179  m_column_widths.clear();
180  gint *col_widths_int = g_key_file_get_integer_list (keyfile, group.c_str(), CSV_COL_WIDTHS,
181  &list_len, &key_error);
182  for (uint32_t i = 0; i < list_len; i++)
183  {
184  if (col_widths_int[i] > 0)
185  m_column_widths.push_back(col_widths_int[i]);
186  }
187  m_load_error |= handle_load_error (&key_error, group);
188  if (col_widths_int)
189  g_free (col_widths_int);
190 
191  return m_load_error;
192 }
193 
194 /**************************************************
195  * save_common
196  *
197  * save settings to a key file
198  **************************************************/
199 bool
201 {
202  auto keyfile = gnc_state_get_current ();
203  auto group = get_group_prefix() + m_name;
204 
205  // Start Saving the Common settings
206  g_key_file_set_string (keyfile, group.c_str(), CSV_NAME, m_name.c_str());
207 
208  g_key_file_set_integer (keyfile, group.c_str(), CSV_SKIP_START, m_skip_start_lines);
209  g_key_file_set_integer (keyfile, group.c_str(), CSV_SKIP_END, m_skip_end_lines);
210  g_key_file_set_boolean (keyfile, group.c_str(), CSV_SKIP_ALT, m_skip_alt_lines);
211  g_key_file_set_boolean (keyfile, group.c_str(), CSV_FORMAT,
212  (m_file_format == GncImpFileFormat::CSV) ? true : false);
213 
214  g_key_file_set_string (keyfile, group.c_str(), CSV_SEP, m_separators.c_str());
215  g_key_file_set_boolean (keyfile, group.c_str(), CSV_ESC, m_enable_escape);
216  g_key_file_set_integer (keyfile, group.c_str(), CSV_DATE, m_date_format);
217  std::ostringstream cmt_ss;
218  cmt_ss << "Supported date formats: ";
219  int fmt_num = 0;
220  std::for_each (GncDate::c_formats.cbegin(), GncDate::c_formats.cend(),
221  [&cmt_ss, &fmt_num](const GncDateFormat& fmt)
222  { cmt_ss << fmt_num++ << ": '" << fmt.m_fmt << "', "; });
223  auto cmt = cmt_ss.str().substr(0, static_cast<long>(cmt_ss.tellp()) - 2);
224  g_key_file_set_comment (keyfile, group.c_str(), CSV_DATE, cmt.c_str(), nullptr);
225  g_key_file_set_integer (keyfile, group.c_str(), CSV_CURRENCY, m_currency_format);
226  g_key_file_set_string (keyfile, group.c_str(), CSV_ENCODING, m_encoding.c_str());
227 
228  if (!m_column_widths.empty())
229  g_key_file_set_integer_list (keyfile, group.c_str(), CSV_COL_WIDTHS,
230  (gint*)(m_column_widths.data()), m_column_widths.size());
231 
232  // Do a test read of encoding
233  GError *key_error = nullptr;
234  bool error = false;
235  auto enc_val = g_key_file_get_string (keyfile, group.c_str(), CSV_ENCODING, &key_error);
236  auto enc_str = std::string{enc_val};
237  if (enc_val)
238  g_free (enc_val);
239 
240  if ((key_error) || (enc_str != m_encoding.c_str()))
241  {
242  if (key_error)
243  {
244  g_warning ("Error reading group %s key %s: %s", group.c_str(), CSV_ENCODING, key_error->message);
245  g_error_free (key_error);
246  }
247  else
248  g_warning ("Error comparing group %s key %s: '%s' and '%s'", group.c_str(), CSV_ENCODING, enc_str.c_str(), group.c_str());
249  error = true;
250  }
251  return error;
252 }
253 
254 void
256 {
257  auto keyfile = gnc_state_get_current ();
258  auto group = get_group_prefix() + m_name;
259  g_key_file_remove_group (keyfile, group.c_str(), nullptr);
260 }
Functions to load, save and get gui state.
utility functions for the GnuCash UI
CSV Import Settings.
GKeyFile * gnc_state_get_current(void)
Returns a pointer to the most recently loaded state.
Definition: gnc-state.c:248
Account handling public routines.
bool preset_is_reserved_name(const std::string &name)
Check whether name can be used as a preset name.
bool load(void)
Load the widget properties from a key File.
const std::string m_fmt
A string representing the format.
void remove(void)
Remove the preset from the state file.
bool save(void)
Save the gathered widget properties to a key File.
static const std::vector< GncDateFormat > c_formats
A vector with all the date formats supported by the string constructor.