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 
58 #define CSV_CUSTOM "Custom"
59 #define CSV_CUSTOM_ENTRY "CustomEntry"
60 
61 #define CSV_DATE "DateFormat"
62 #define CSV_CURRENCY "CurrencyFormat"
63 
64 #define CSV_ENCODING "Encoding"
65 #define CSV_COL_WIDTHS "ColumnWidths"
66 
67 G_GNUC_UNUSED static QofLogModule log_module = GNC_MOD_IMPORT;
68 
69 /**************************************************
70  * handle_load_error
71  *
72  * record possible errors in the log file
73  * ignore key-not-found errors though. We'll just
74  * use a default value and go on.
75  **************************************************/
76 bool
77 handle_load_error (GError **key_error, const std::string& group)
78 {
79  if (!*key_error)
80  return false;
81 
82  if ((*key_error)->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND)
83  {
84  g_clear_error (key_error);
85  return false;
86  }
87 
88  g_warning ("Error reading group '%s' : %s", group.c_str(), (*key_error)->message);
89  g_clear_error (key_error);
90  return true;
91 }
92 
93 bool preset_is_reserved_name (const std::string& name)
94 {
95  return ((name == no_settings) ||
96  (name == _(no_settings.c_str())) ||
97  (name == gnc_exp) ||
98  (name == _(gnc_exp.c_str())));
99 }
100 
101 std::string get_no_settings (void)
102 {
103  return no_settings;
104 }
105 
106 std::string get_gnc_exp (void)
107 {
108  return gnc_exp;
109 }
110 
111 std::string get_gnc_exp_4 (void)
112 {
113  return gnc_exp_4;
114 }
115 
116 /**************************************************
117  * load_common
118  *
119  * load the settings from a state key file
120  **************************************************/
121 bool
123 {
124  GError *key_error = nullptr;
125  m_load_error = false;
126  auto group = get_group_prefix() + m_name;
127  auto keyfile = gnc_state_get_current ();
128 
129  m_skip_start_lines = g_key_file_get_integer (keyfile, group.c_str(), CSV_SKIP_START, &key_error);
130  m_load_error |= handle_load_error (&key_error, group);
131 
132  m_skip_end_lines = g_key_file_get_integer (keyfile, group.c_str(), CSV_SKIP_END, &key_error);
133  m_load_error |= handle_load_error (&key_error, group);
134 
135  m_skip_alt_lines = g_key_file_get_boolean (keyfile, group.c_str(), CSV_SKIP_ALT, &key_error);
136  m_load_error |= handle_load_error (&key_error, group);
137 
138  auto csv_format = g_key_file_get_boolean (keyfile, group.c_str(), CSV_FORMAT, &key_error);
139  if (key_error) csv_format = true; // default to true, but above command will return false in case of error
140  m_load_error |= handle_load_error (&key_error, group);
141  if (csv_format)
142  m_file_format = GncImpFileFormat::CSV;
143  else
144  m_file_format = GncImpFileFormat::FIXED_WIDTH;
145 
146  gchar *key_char = g_key_file_get_string (keyfile, group.c_str(), CSV_SEP, &key_error);
147  if (key_char && *key_char != '\0')
148  m_separators = key_char;
149  m_load_error |= handle_load_error (&key_error, group);
150  if (key_char)
151  g_free (key_char);
152 
153  m_date_format = g_key_file_get_integer (keyfile, group.c_str(), CSV_DATE, &key_error);
154  m_load_error |= handle_load_error (&key_error, group);
155 
156  m_currency_format = g_key_file_get_integer (keyfile, group.c_str(), CSV_CURRENCY, &key_error);
157  m_load_error |= handle_load_error (&key_error, group);
158 
159  key_char = g_key_file_get_string (keyfile, group.c_str(), CSV_ENCODING, &key_error);
160  if (key_char && *key_char != '\0')
161  m_encoding = key_char;
162  else
163  m_encoding = "UTF-8";
164  m_load_error |= handle_load_error (&key_error, group);
165  if (key_char)
166  g_free (key_char);
167 
168  // Widths
169  gsize list_len;
170  m_column_widths.clear();
171  gint *col_widths_int = g_key_file_get_integer_list (keyfile, group.c_str(), CSV_COL_WIDTHS,
172  &list_len, &key_error);
173  for (uint32_t i = 0; i < list_len; i++)
174  {
175  if (col_widths_int[i] > 0)
176  m_column_widths.push_back(col_widths_int[i]);
177  }
178  m_load_error |= handle_load_error (&key_error, group);
179  if (col_widths_int)
180  g_free (col_widths_int);
181 
182  return m_load_error;
183 }
184 
185 /**************************************************
186  * save_common
187  *
188  * save settings to a key file
189  **************************************************/
190 bool
192 {
193  auto keyfile = gnc_state_get_current ();
194  auto group = get_group_prefix() + m_name;
195 
196  // Start Saving the Common settings
197  g_key_file_set_string (keyfile, group.c_str(), CSV_NAME, m_name.c_str());
198 
199  g_key_file_set_integer (keyfile, group.c_str(), CSV_SKIP_START, m_skip_start_lines);
200  g_key_file_set_integer (keyfile, group.c_str(), CSV_SKIP_END, m_skip_end_lines);
201  g_key_file_set_boolean (keyfile, group.c_str(), CSV_SKIP_ALT, m_skip_alt_lines);
202  g_key_file_set_boolean (keyfile, group.c_str(), CSV_FORMAT,
203  (m_file_format == GncImpFileFormat::CSV) ? true : false);
204 
205  g_key_file_set_string (keyfile, group.c_str(), CSV_SEP, m_separators.c_str());
206  g_key_file_set_integer (keyfile, group.c_str(), CSV_DATE, m_date_format);
207  std::ostringstream cmt_ss;
208  cmt_ss << "Supported date formats: ";
209  int fmt_num = 0;
210  std::for_each (GncDate::c_formats.cbegin(), GncDate::c_formats.cend(),
211  [&cmt_ss, &fmt_num](const GncDateFormat& fmt)
212  { cmt_ss << fmt_num++ << ": '" << fmt.m_fmt << "', "; });
213  auto cmt = cmt_ss.str().substr(0, static_cast<long>(cmt_ss.tellp()) - 2);
214  g_key_file_set_comment (keyfile, group.c_str(), CSV_DATE, cmt.c_str(), nullptr);
215  g_key_file_set_integer (keyfile, group.c_str(), CSV_CURRENCY, m_currency_format);
216  g_key_file_set_string (keyfile, group.c_str(), CSV_ENCODING, m_encoding.c_str());
217 
218  if (!m_column_widths.empty())
219  g_key_file_set_integer_list (keyfile, group.c_str(), CSV_COL_WIDTHS,
220  (gint*)(m_column_widths.data()), m_column_widths.size());
221 
222  // Do a test read of encoding
223  GError *key_error = nullptr;
224  bool error = false;
225  auto enc_val = g_key_file_get_string (keyfile, group.c_str(), CSV_ENCODING, &key_error);
226  auto enc_str = std::string{enc_val};
227  if (enc_val)
228  g_free (enc_val);
229 
230  if ((key_error) || (enc_str != m_encoding.c_str()))
231  {
232  if (key_error)
233  {
234  g_warning ("Error reading group %s key %s: %s", group.c_str(), CSV_ENCODING, key_error->message);
235  g_error_free (key_error);
236  }
237  else
238  g_warning ("Error comparing group %s key %s: '%s' and '%s'", group.c_str(), CSV_ENCODING, enc_str.c_str(), group.c_str());
239  error = true;
240  }
241  return error;
242 }
243 
244 void
246 {
247  auto keyfile = gnc_state_get_current ();
248  auto group = get_group_prefix() + m_name;
249  g_key_file_remove_group (keyfile, group.c_str(), nullptr);
250 }
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.