3
* Copyright (C) 2001-2004 Murray Cumming
5
* This program is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU General Public License as
7
* published by the Free Software Foundation; either version 2 of the
8
* License, or (at your option) any later version.
10
* This program is distributed in the hope that it will be useful, but
11
* WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* General Public License for more details.
15
* You should have received a copy of the GNU General Public
16
* License along with this program; if not, write to the
17
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18
* Boston, MA 02111-1307, USA.
21
#include "dialog_import_csv.h"
22
#include <glom/import_csv/file_encodings.h>
23
#include <libglom/libglom_config.h>
25
#include <libglom/data_structure/glomconversions.h>
27
#include <gtkmm/messagedialog.h>
28
#include <gtkmm/cellrenderercombo.h>
29
#include <glom/utils_ui.h>
30
#include <glibmm/i18n.h>
36
// When auto-detecting the encoding, we try to read the file in these
37
// encodings, in order:
38
const char* AUTODETECT_ENCODINGS_CHARSETS[] = {
47
const guint N_AUTODETECT_ENCODINGS_CHARSETS = sizeof(AUTODETECT_ENCODINGS_CHARSETS)/sizeof(AUTODETECT_ENCODINGS_CHARSETS[0]);
50
Glib::ustring encoding_display(const Glib::ustring& name, const Glib::ustring& charset)
55
return name + " (" + charset + ")";
58
} //anonymous namespace
63
Dialog_Import_CSV::Dialog_Import_CSV(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& builder)
64
: Gtk::Dialog(cobject),
65
m_auto_detect_encoding(),
68
builder->get_widget("import_csv_fields", m_sample_view);
69
builder->get_widget("import_csv_target_table", m_target_table);
70
builder->get_widget("import_csv_encoding", m_encoding_combo);
71
builder->get_widget("import_csv_encoding_info", m_encoding_info);
72
builder->get_widget("import_csv_first_line_as_title", m_first_line_as_title);
73
builder->get_widget("import_csv_sample_rows", m_sample_rows);
74
builder->get_widget("import_csv_advice_label", m_advice_label);
75
builder->get_widget("import_csv_error_label", m_error_label);
76
#ifdef GLIBMM_EXCEPTIONS_ENABLED
77
if(!m_sample_view || !m_encoding_combo || !m_target_table || !m_encoding_info || !m_first_line_as_title || !m_sample_rows || !m_error_label)
78
throw std::runtime_error("Missing widgets from glade file for Dialog_Import_CSV");
81
//Fill the list of encodings:
82
m_encoding_model = Gtk::ListStore::create(m_encoding_columns);
84
Gtk::TreeModel::iterator iter = m_encoding_model->append();
85
(*iter)[m_encoding_columns.m_col_name] = _("Auto Detect");
88
m_encoding_model->append();
90
const FileEncodings::type_list_encodings list_encodings = FileEncodings::get_list_of_encodings();
91
for(FileEncodings::type_list_encodings::const_iterator encodings_iter = list_encodings.begin(); encodings_iter != list_encodings.end(); encodings_iter ++)
93
const FileEncodings::Encoding encoding = *encodings_iter;
94
if(encoding.get_name().empty())
97
iter = m_encoding_model->append();
98
Gtk::TreeModel::Row row = *iter;
99
row[m_encoding_columns.m_col_name] = encoding.get_name();
100
row[m_encoding_columns.m_col_charset] = encoding.get_charset();
103
m_sample_rows->set_value(2); //A sensible default.
105
Gtk::CellRendererText* renderer = Gtk::manage(new Gtk::CellRendererText);
106
m_encoding_combo->set_model(m_encoding_model);
107
m_encoding_combo->pack_start(*renderer);
108
m_encoding_combo->set_cell_data_func(*renderer, sigc::bind(sigc::mem_fun(*this, &Dialog_Import_CSV::encoding_data_func), sigc::ref(*renderer)));
109
m_encoding_combo->set_row_separator_func(sigc::mem_fun(*this, &Dialog_Import_CSV::row_separator_func));
110
m_encoding_combo->set_active(0);
112
m_encoding_combo->signal_changed().connect(sigc::mem_fun(*this, &Dialog_Import_CSV::on_combo_encoding_changed));
114
// TODO: Reset parser encoding on selection changed.
115
m_parser = std::auto_ptr<CsvParser>(new CsvParser(get_current_encoding().c_str()));
116
m_parser->signal_file_read_error().connect(sigc::mem_fun(*this, &Dialog_Import_CSV::on_parser_file_read_error));
117
m_parser->signal_have_display_name().connect(sigc::mem_fun(*this, &Dialog_Import_CSV::on_parser_have_display_name));
118
m_parser->signal_encoding_error().connect(sigc::mem_fun(*this, &Dialog_Import_CSV::on_parser_encoding_error));
119
m_parser->signal_line_scanned().connect(sigc::mem_fun(*this, &Dialog_Import_CSV::on_parser_line_scanned));
120
m_parser->signal_state_changed().connect(sigc::mem_fun(*this, &Dialog_Import_CSV::on_parser_state_changed));
122
m_first_line_as_title->set_active(false);
123
m_first_line_as_title->signal_toggled().connect(sigc::mem_fun(*this, &Dialog_Import_CSV::on_first_line_as_title_toggled));
124
m_sample_rows->signal_changed().connect(sigc::mem_fun(*this, &Dialog_Import_CSV::on_sample_rows_changed));
126
m_sample_view->set_headers_visible(m_first_line_as_title->get_active());
129
//Warn the user about the numeric and date formats expected:
131
//A date that is really really the date that we mean:
133
memset(&the_c_time, 0, sizeof(the_c_time));
135
//We mean 22nd November 2008:
136
the_c_time.tm_year = 2008 - 1900; //C years start are the AD year - 1900. So, 01 is 1901.
137
the_c_time.tm_mon = 11 - 1; //C months start at 0.
138
the_c_time.tm_mday = 22; //starts at 1
140
//Get the ISO (not current locale) text representation:
141
const Glib::ustring date_text = Glom::Conversions::format_date(the_c_time, std::locale() /* ignored */, true /* iso_format */);
142
const Glib::ustring advice = Glib::ustring::compose(_("Note that the source file should contain numbers and dates in international ISO format. For instance, 22nd November 2008 should be %1."), date_text);
143
m_advice_label->set_text(advice);
144
std::cout << "DEBUG: advice=" << advice << std::endl;
149
CsvParser::State Dialog_Import_CSV::get_parser_state() const
151
return m_parser->get_state();
154
Glib::ustring Dialog_Import_CSV::get_target_table_name() const
156
return m_target_table->get_text();
159
const Glib::ustring& Dialog_Import_CSV::get_file_uri() const
164
void Dialog_Import_CSV::import(const Glib::ustring& uri, const Glib::ustring& into_table)
168
Document* document = get_document();
171
show_error_dialog(_("No Document Available"), _("You need to open a document to import the data into a table."));
175
// Make the relevant widgets sensitive. We will make them insensitive
176
// again when a (non-recoverable) error occurs.
177
m_sample_view->set_sensitive();
178
m_encoding_combo->set_sensitive();
179
m_first_line_as_title->set_sensitive();
180
m_sample_rows->set_sensitive();
182
set_title(_("Import From CSV File"));
183
m_target_table->set_markup("<b>" + Glib::Markup::escape_text(into_table) + "</b>");
185
m_field_model = Gtk::ListStore::create(m_field_columns);
186
Gtk::TreeModel::iterator tree_iter = m_field_model->append();
187
(*tree_iter)[m_field_columns.m_col_field_name] = _("<None>");
189
const Document::type_vec_fields fields(document->get_table_fields(into_table));
190
for(Document::type_vec_fields::const_iterator iter = fields.begin(); iter != fields.end(); ++ iter)
192
sharedptr<Field> field = *iter;
196
// Don't allow the primary key to be selected when it is an auto
197
// increment key, since the value for the primary key is chosen
198
// automatically anyway.
199
if(!field->get_primary_key() || !field->get_auto_increment())
201
Gtk::TreeModel::iterator tree_iter = m_field_model->append();
202
(*tree_iter)[m_field_columns.m_col_field] = *iter;
203
(*tree_iter)[m_field_columns.m_col_field_name] = (*iter)->get_name();
207
// Create the sorted version of this model,
208
// so the user sees the fields in alphabetical order:
209
m_field_model_sorted = Gtk::TreeModelSort::create(m_field_model);
210
m_field_model_sorted->set_sort_column(m_field_columns.m_col_field_name, Gtk::SORT_ASCENDING);
213
m_parser->set_file_and_start_parsing(uri);
217
guint Dialog_Import_CSV::get_column_count() const
222
sharedptr<const Field> Dialog_Import_CSV::get_field_for_column(guint col) const
224
return m_fields[col];
227
const Glib::ustring& Dialog_Import_CSV::get_data(guint row, guint col)
229
if(m_first_line_as_title->get_active())
232
return m_parser->get_data(row, col);
235
CsvParser& Dialog_Import_CSV::get_parser()
237
return *(m_parser.get());
240
void Dialog_Import_CSV::clear()
242
// TODO: Do we explicitely need to cancel async operations?
243
// TODO: Disconnect idle handlers
244
m_sample_model.reset();
245
m_sample_view->remove_all_columns();
246
m_sample_view->set_model(m_sample_model);
247
m_field_model.reset();
248
m_field_model_sorted.reset();
253
m_encoding_info->set_text("");
254
m_sample_view->set_sensitive(false);
255
m_encoding_combo->set_sensitive(false);
256
m_first_line_as_title->set_sensitive(false);
257
m_sample_rows->set_sensitive(false);
259
validate_primary_key();
262
void Dialog_Import_CSV::show_error_dialog(const Glib::ustring&, const Glib::ustring& secondary)
264
Utils::show_ok_dialog(_("Error Importing CSV File"),
265
secondary, *this, Gtk::MESSAGE_ERROR);
268
void Dialog_Import_CSV::encoding_data_func(const Gtk::TreeModel::iterator& iter, Gtk::CellRendererText& renderer)
270
const Glib::ustring name = (*iter)[m_encoding_columns.m_col_name];
271
const Glib::ustring charset = (*iter)[m_encoding_columns.m_col_charset];
273
renderer.set_property("text", encoding_display(name, charset));
276
bool Dialog_Import_CSV::row_separator_func(const Glib::RefPtr<Gtk::TreeModel>& /* model */, const Gtk::TreeModel::iterator& iter) const
278
return (*iter)[m_encoding_columns.m_col_name] == "";
282
void Dialog_Import_CSV::on_combo_encoding_changed()
284
const int active = m_encoding_combo->get_active_row_number();
288
case -1: // No active item
289
g_assert_not_reached();
291
case 0: // Auto-Detect
292
// Begin with first encoding
293
m_auto_detect_encoding = 0;
295
default: // Some specific encoding
296
m_auto_detect_encoding = -1;
300
// Parse from beginning with new encoding:
301
m_parser->set_encoding(get_current_encoding());
302
m_parser->set_file_and_start_parsing(m_file_uri);
305
void Dialog_Import_CSV::on_first_line_as_title_toggled()
307
// Ignore if we don't have a model yet, we will take care of the option
308
// later when inserting items into it.
312
if(m_first_line_as_title->get_active())
314
m_sample_view->set_headers_visible(true);
315
Gtk::TreeModel::Path path("1");
316
Gtk::TreeModel::iterator iter = m_sample_model->get_iter(path);
318
// Remove the first row from the view
319
if(iter && (*iter)[m_sample_columns.m_col_row] == 0)
321
m_sample_model->erase(iter);
323
// Add another row to the end, if one is loaded.
324
const guint last_index = m_sample_model->children().size();
325
iter = m_sample_model->append();
326
(*iter)[m_sample_columns.m_col_row] = last_index;
331
m_sample_view->set_headers_visible(false);
333
// Check whether row 0 is displayed
334
Gtk::TreeModel::Path path("1");
335
Gtk::TreeModel::iterator iter = m_sample_model->get_iter(path);
337
//if((!iter || (*iter)[m_sample_columns.m_col_row] != 0) && !m_parser->get_rows_empty() && m_sample_rows->get_value_as_int() > 0)
338
if((!iter || (*iter)[m_sample_columns.m_col_row] != 0) &&
339
m_sample_rows->get_value_as_int() > 0)
341
// Add first row to model
343
iter = m_sample_model->append();
345
iter = m_sample_model->insert(iter);
347
(*iter)[m_sample_columns.m_col_row] = 0;
349
// Remove last row if we hit the limit
350
const guint sample_rows = m_sample_model->children().size() - 1;
351
if(sample_rows > static_cast<guint>(m_sample_rows->get_value_as_int()))
353
//m_sample_model->erase(m_sample_model->children().rbegin());
354
path[0] = sample_rows;
355
iter = m_sample_model->get_iter(path);
356
m_sample_model->erase(iter);
362
void Dialog_Import_CSV::on_sample_rows_changed()
364
// Ignore if we don't have a model yet, we will take care of the option
365
// later when inserting items into it.
369
const guint current_sample_rows = m_sample_model->children().size() - 1;
370
const guint new_sample_rows = m_sample_rows->get_value_as_int();
372
if(current_sample_rows > new_sample_rows)
374
// +1 for the "target field" row
375
Gtk::TreeModel::Path path(1);
376
path[0] = new_sample_rows + 1;
377
Gtk::TreeModel::iterator iter = m_sample_model->get_iter(path);
379
while(iter != m_sample_model->children().end())
380
iter = m_sample_model->erase(iter);
384
// Find index of first row to add
385
guint row_index = current_sample_rows;
386
if(m_first_line_as_title->get_active())
389
for(guint i = current_sample_rows; i < new_sample_rows; ++i, ++row_index)
391
Gtk::TreeModel::iterator iter = m_sample_model->append();
392
(*iter)[m_sample_columns.m_col_row] = row_index;
397
Glib::ustring Dialog_Import_CSV::get_current_encoding() const
399
Gtk::TreeModel::iterator iter = m_encoding_combo->get_active();
400
const Glib::ustring encoding = (*iter)[m_encoding_columns.m_col_charset];
405
g_assert(m_auto_detect_encoding != -1);
406
return AUTODETECT_ENCODINGS_CHARSETS[m_auto_detect_encoding];
412
void Dialog_Import_CSV::begin_parse()
414
if(m_auto_detect_encoding != -1)
416
const char* encoding_charset = AUTODETECT_ENCODINGS_CHARSETS[m_auto_detect_encoding];
417
const Glib::ustring encoding_name = FileEncodings::get_name_of_charset(encoding_charset);
418
m_encoding_info->set_text(Glib::ustring::compose(_("Encoding detected as: %1"), encoding_display(encoding_name, encoding_charset)));
421
m_encoding_info->set_text("");
423
// Clear sample preview since we reparse everything, perhaps with
425
m_sample_model.reset();
426
m_sample_view->remove_all_columns();
427
m_sample_view->set_model(m_sample_model); // Empty model
430
m_parser->set_encoding(get_current_encoding().c_str());
432
// Allow the Import button to be pressed when a field for the primary key
433
// field is set. When the import button is pressed without the file being
434
// fully loaded, the import progress waits for us to load the rest.
435
validate_primary_key();
438
void Dialog_Import_CSV::on_parser_encoding_error()
441
// Clear sample preview (TODO: Let it visible, and only remove when reparsing?)
442
m_sample_model.reset();
443
m_sample_view->remove_all_columns();
444
m_sample_view->set_model(m_sample_model); // Empty model
446
// Don't allow the import button to be pressed when an error occured. This
447
// would not make sense since we cleared all the parsed row data anyway.
448
validate_primary_key();
450
// If we are auto-detecting the encoding, then try the next one
451
if(m_auto_detect_encoding != -1)
453
++ m_auto_detect_encoding;
454
if(static_cast<guint>(m_auto_detect_encoding) < N_AUTODETECT_ENCODINGS_CHARSETS)
457
m_encoding_info->set_text(_("Encoding detection failed. Please manually choose one from the box."));
461
m_encoding_info->set_text(_("The file contains data not in the specified encoding. Please choose another one, or try \"Auto Detect\"."));
465
void Dialog_Import_CSV::on_parser_line_scanned(CsvParser::type_row_strings row, unsigned int row_number)
467
// This is the first line read if there is no model yet:
470
setup_sample_model(row);
471
Gtk::TreeModel::iterator iter = m_sample_model->append();
472
// -1 means the row to select target fields (see special handling in cell data funcs)
473
(*iter)[m_sample_columns.m_col_row] = -1;
476
// Add the row to the treeview if there are not yet as much sample rows
477
// as the user has chosen (note the first row is to choose the target fields,
478
// not a sample row, which is why we do -1 here).
479
const guint sample_rows = m_sample_model->children().size() - 1;
481
// Don't add if this is the first line and m_first_line_as_title is active:
482
if(row_number > 1 || !m_first_line_as_title->get_active())
484
if(sample_rows < static_cast<guint>(m_sample_rows->get_value_as_int()))
486
Gtk::TreeModel::iterator tree_iter = m_sample_model->append();
487
(*tree_iter)[m_sample_columns.m_col_row] = row_number;
492
void Dialog_Import_CSV::setup_sample_model(const CsvParser::type_row_strings& row)
494
m_sample_model = Gtk::ListStore::create(m_sample_columns);
495
m_sample_view->set_model(m_sample_model);
497
// Create field vector that contains the fields into which to import
499
m_fields.resize(row.size());
501
// Start with a column showing the line number.
502
Gtk::CellRendererText* text = Gtk::manage(new Gtk::CellRendererText);
503
Gtk::TreeViewColumn* col = Gtk::manage(new Gtk::TreeViewColumn(_("Line")));
504
col->pack_start(*text, false);
505
col->set_cell_data_func(*text, sigc::mem_fun(*this, &Dialog_Import_CSV::line_data_func));
506
m_sample_view->append_column(*col);
508
m_cols_count = row.size();
510
for(guint i = 0; i < m_cols_count; ++ i)
512
const Glib::ustring& data = row[i];
513
m_sample_view->append_column(*Gtk::manage(create_sample_column(data, i)));
517
Gtk::TreeViewColumn* Dialog_Import_CSV::create_sample_column(const Glib::ustring& title, guint index)
519
Gtk::TreeViewColumn* col = new Gtk::TreeViewColumn(title);
520
Gtk::CellRendererCombo* cell = create_sample_cell(index);
521
col->pack_start(*Gtk::manage(cell), true);
522
col->set_cell_data_func(*cell, sigc::bind(sigc::mem_fun(*this, &Dialog_Import_CSV::field_data_func), index));
523
col->set_sizing(Gtk::TREE_VIEW_COLUMN_AUTOSIZE);
527
Gtk::CellRendererCombo* Dialog_Import_CSV::create_sample_cell(guint index)
529
Gtk::CellRendererCombo* cell = new Gtk::CellRendererCombo;
530
#ifdef GLIBMM_PROPERTIES_ENABLED
531
cell->property_model() = m_field_model_sorted;
532
cell->property_text_column() = 0;
533
cell->property_has_entry() = false;
535
cell->set_property("model", m_field_model_sorted);
536
cell->set_property("text-column", 0);
537
cell->set_property("has_entry", false);
539
cell->signal_edited().connect(sigc::bind(sigc::mem_fun(*this, &Dialog_Import_CSV::on_field_edited), index));
544
void Dialog_Import_CSV::line_data_func(Gtk::CellRenderer* renderer, const Gtk::TreeModel::iterator& iter)
546
const int row = (*iter)[m_sample_columns.m_col_row];
547
Gtk::CellRendererText* renderer_text = dynamic_cast<Gtk::CellRendererText*>(renderer);
548
#ifdef GLIBMM_EXCEPTIONS_ENABLED
550
throw std::logic_error("CellRenderer is not a CellRendererText in line_data_func");
554
renderer_text->set_property("text", Glib::ustring(_("Target Field")));
556
renderer_text->set_property("text", Glib::ustring::compose("%1", row + 1));
559
void Dialog_Import_CSV::field_data_func(Gtk::CellRenderer* renderer, const Gtk::TreeModel::iterator& iter, guint column_number)
561
const int row = (*iter)[m_sample_columns.m_col_row];
562
Gtk::CellRendererCombo* renderer_combo = dynamic_cast<Gtk::CellRendererCombo*>(renderer);
563
#ifdef GLIBMM_EXCEPTIONS_ENABLED
564
if(!renderer_combo) throw std::logic_error("CellRenderer is not a CellRendererCombo in field_data_func");
568
bool editable = false;
572
sharedptr<Field> field = m_fields[column_number];
574
text = field->get_name();
582
// Convert to currently chosen field, if any, and back, too see how it
583
// looks like when imported:
585
if(column_number < m_fields.size())
587
sharedptr<Field> field = m_fields[column_number];
589
if(row != -1) // && static_cast<unsigned int>(row) < m_parser->get_rows_count())
591
const Glib::ustring& orig_text = m_parser->get_data(row, column_number);
595
if(field->get_glom_type() != Field::TYPE_IMAGE)
597
/* Exported data is always stored in postgres format */
598
bool success = false;
599
const Gnome::Gda::Value value = field->from_file_format(orig_text, success);
601
text = _("<Import Failure>");
603
text = Glom::Conversions::get_text_for_gda_value(field->get_glom_type(), value);
607
// TODO: It is too slow to create the picture here. Maybe we should
608
// create it once and cache it. We could also think about using a
609
// GtkCellRendererPixbuf to show it, then.
610
if(!orig_text.empty() && orig_text != "NULL")
611
text = _("<Picture>");
616
// TODO: Should we unescape the field's content?
620
if(text.length() > 32)
631
renderer_combo->set_property("text", text);
632
renderer_combo->set_property("editable", editable);
636
/** Parse a row from a .cvs file. Note that this "line" might have newline
637
* characters inside one field value, inside quotes.
639
void Dialog_Import_CSV::on_field_edited(const Glib::ustring& path, const Glib::ustring& new_text, guint column_number)
641
Gtk::TreeModel::Path treepath(path);
642
Gtk::TreeModel::iterator iter = m_sample_model->get_iter(treepath);
644
// Lookup field indicated by new_text
645
const Gtk::TreeNodeChildren& children = m_field_model->children();
646
for(Gtk::TreeModel::iterator field_iter = children.begin(); field_iter != children.end(); ++ field_iter)
648
if( (*field_iter)[m_field_columns.m_col_field_name] == new_text)
650
sharedptr<Field> field = (*field_iter)[m_field_columns.m_col_field];
651
// Check whether another column is already using that field
652
type_vec_fields::iterator vec_field_iter = std::find(m_fields.begin(), m_fields.end(), field);
653
// Reset the old column since two different columns cannot be imported into the same field
654
if(vec_field_iter != m_fields.end()) *vec_field_iter = sharedptr<Field>();
656
m_fields[column_number] = field;
658
// Update the rows, so they are redrawn, doing a conversion to the new type.
659
const Gtk::TreeNodeChildren& sample_children = m_sample_model->children();
660
// Create a TreeModel::Path with initial index 0. We need a TreeModel::Path for the row_changed() call
661
Gtk::TreeModel::Path path("0");
663
for(Gtk::TreeModel::iterator sample_iter = sample_children.begin(); sample_iter != sample_children.end(); ++ sample_iter)
665
if(sample_iter != iter)
666
m_sample_model->row_changed(path, sample_iter);
671
validate_primary_key();
677
void Dialog_Import_CSV::validate_primary_key()
679
if(get_parser_state() == (CsvParser::STATE_NONE | CsvParser::STATE_ENCODING_ERROR))
681
m_error_label->hide();
682
set_response_sensitive(Gtk::RESPONSE_ACCEPT, false);
686
// Allow the import button to be pressed when the value for the primary key
688
sharedptr<Field> primary_key = get_field_primary_key_for_table(get_target_table_name());
689
bool primary_key_selected = false;
691
if(primary_key && !primary_key->get_auto_increment())
693
// If m_rows is empty, then no single line was read from the file yet,
694
// and the m_fields array is not up to date. It is set in handle_line()
695
// when the first line is parsed.
696
primary_key_selected = false;
697
if(!m_parser->get_rows_empty())
699
for(type_vec_fields::iterator iter = m_fields.begin(); iter != m_fields.end(); ++ iter)
701
if(*iter == primary_key)
703
primary_key_selected = true;
709
if(!primary_key_selected)
710
m_error_label->set_markup(Glib::ustring::compose(_("One column needs to be assigned the table's primary key (<b>%1</b>) as target field before importing"), Glib::Markup::escape_text(primary_key->get_name())));
714
// auto_increment primary keys always work since their value is
715
// assigned automatically.
716
primary_key_selected = true;
719
set_response_sensitive(Gtk::RESPONSE_ACCEPT, primary_key_selected);
720
if(primary_key_selected)
721
m_error_label->hide();
723
m_error_label->show();
727
void Dialog_Import_CSV::on_parser_file_read_error(const Glib::ustring& error_message)
729
std::string filename;
730
#ifdef GLIBMM_EXCEPTIONS_ENABLED
733
filename = Glib::filename_from_uri(m_file_uri);
735
catch(const Glib::ConvertError& ex)
737
std::cerr << "Glib::filename_from_uri() failed: " << ex.what() << std::endl;
740
std::auto_ptr<Glib::Error> error;
741
filename = Glib::filename_from_uri(m_file_uri, error);
744
show_error_dialog(_("Could Not Open file"),
745
Glib::ustring::compose(_("The file at \"%1\" could not be opened: %2"), filename, error_message) );
748
void Dialog_Import_CSV::on_parser_have_display_name(const Glib::ustring& display_name)
750
set_title(display_name + _(" - Import From CSV File"));
753
void Dialog_Import_CSV::on_parser_state_changed()
755
//Remit (via our similarly-named signal) this so that the progress dialog can respond:
756
signal_state_changed().emit();
759
Dialog_Import_CSV::type_signal_state_changed Dialog_Import_CSV::signal_state_changed() const
761
return m_signal_state_changed;