Go to the documentation of this file.00001 #include "dataload_csv.h"
00002 #include <QTextStream>
00003 #include <QFile>
00004 #include <QMessageBox>
00005 #include <QDebug>
00006 #include <QSettings>
00007 #include <QProgressDialog>
00008 #include "selectlistdialog.h"
00009
00010 DataLoadCSV::DataLoadCSV()
00011 {
00012 _extensions.push_back( "csv");
00013 }
00014
00015 const QRegExp csv_separator("(\\,|\\;|\\|)");
00016
00017 const std::vector<const char*> &DataLoadCSV::compatibleFileExtensions() const
00018 {
00019 return _extensions;
00020 }
00021
00022 QSize DataLoadCSV::parseHeader(QFile *file, std::vector<std::string>& ordered_names)
00023 {
00024 QTextStream inA(file);
00025
00026 QString first_line = inA.readLine();
00027 QString second_line = inA.readLine();
00028
00029 QStringList firstline_items = first_line.split(csv_separator);
00030
00031 int linecount = 0;
00032 const int columncount = firstline_items.count();
00033
00034 for (int i=0; i < firstline_items.size(); i++ )
00035 {
00036
00037 QString field_name ( firstline_items[i] );
00038
00039 if( field_name.isEmpty())
00040 {
00041 field_name = QString("_Column_%1").arg(i);
00042 }
00043 ordered_names.push_back( field_name.toStdString() );
00044 }
00045
00046 while (!inA.atEnd())
00047 {
00048 inA.readLine();
00049 linecount++;
00050 }
00051
00052 QSize table_size;
00053 table_size.setWidth( columncount);
00054 table_size.setHeight( linecount );
00055 return table_size;
00056 }
00057
00058 bool DataLoadCSV::readDataFromFile(FileLoadInfo* info, PlotDataMapRef& plot_data)
00059 {
00060 bool use_provided_configuration = false;
00061
00062 if( info->plugin_config.hasChildNodes() )
00063 {
00064 use_provided_configuration = true;
00065 xmlLoadState( info->plugin_config.firstChildElement() );
00066 }
00067
00068 const int TIME_INDEX_NOT_DEFINED = -2;
00069
00070 int time_index = TIME_INDEX_NOT_DEFINED;
00071
00072 QFile file( info->filename );
00073 file.open(QFile::ReadOnly);
00074
00075 std::vector<std::string> column_names;
00076
00077 const QSize table_size = parseHeader( &file, column_names);
00078 const int tot_lines = table_size.height() -1;
00079 const int columncount = table_size.width();
00080
00081 file.close();
00082 file.open(QFile::ReadOnly);
00083 QTextStream inB( &file );
00084
00085 std::vector<PlotData*> plots_vector;
00086
00087 bool interrupted = false;
00088
00089 int linecount = 0;
00090
00091 QProgressDialog progress_dialog;
00092 progress_dialog.setLabelText("Loading... please wait");
00093 progress_dialog.setWindowModality( Qt::ApplicationModal );
00094 progress_dialog.setRange(0, tot_lines -1);
00095 progress_dialog.setAutoClose( true );
00096 progress_dialog.setAutoReset( true );
00097 progress_dialog.show();
00098
00099
00100 inB.readLine();
00101
00102
00103 std::deque<std::string> valid_field_names;
00104
00105 for (unsigned i=0; i < column_names.size(); i++ )
00106 {
00107 const std::string& field_name = ( column_names[i] );
00108
00109 auto it = plot_data.addNumeric(field_name);
00110
00111 valid_field_names.push_back( field_name );
00112 plots_vector.push_back( &(it->second) );
00113
00114 if (time_index == TIME_INDEX_NOT_DEFINED && use_provided_configuration)
00115 {
00116 if( _default_time_axis == field_name )
00117 {
00118 time_index = i ;
00119 }
00120 }
00121 }
00122
00123 if( time_index == TIME_INDEX_NOT_DEFINED && !use_provided_configuration)
00124 {
00125 valid_field_names.push_front( "INDEX (auto-generated)" );
00126
00127 SelectFromListDialog* dialog = new SelectFromListDialog( valid_field_names );
00128 dialog->setWindowTitle("Select the time axis");
00129 int res = dialog->exec();
00130
00131 if (res == QDialog::Rejected )
00132 {
00133 return false;
00134 }
00135
00136 const int selected_item = dialog->getSelectedRowNumber().at(0);
00137 if( selected_item > 0)
00138 {
00139 for (unsigned i=0; i< column_names.size(); i++)
00140 {
00141 if( column_names[i] == valid_field_names[selected_item ] )
00142 {
00143 _default_time_axis = column_names[i];
00144 time_index = selected_item -1;
00145 break;
00146 }
00147 }
00148 }
00149 }
00150
00151
00152 double prev_time = - std::numeric_limits<double>::max();
00153 bool monotonic_warning = false;
00154
00155 while (!inB.atEnd() )
00156 {
00157 QString line = inB.readLine();
00158
00159 QStringList string_items = line.split(csv_separator);
00160 if( string_items.size() != columncount)
00161 {
00162 continue;
00163 }
00164 double t = linecount;
00165
00166 if( time_index >= 0)
00167 {
00168 bool is_number = false;
00169 t = string_items[ time_index ].toDouble(&is_number);
00170
00171 if( !is_number)
00172 {
00173 QMessageBox::StandardButton reply;
00174 reply = QMessageBox::warning(0, tr("Error reading file"),
00175 tr("One of the timestamps is not a valid number. Abort\n") );
00176
00177 return false;
00178 }
00179 if( t < prev_time )
00180 {
00181 QMessageBox::StandardButton reply;
00182 reply = QMessageBox::warning(0, tr("Error reading file"),
00183 tr("Selected time in not strictly monotonic. Loading will be aborted\n") );
00184
00185 return false;
00186 }
00187 else if (t == prev_time)
00188 {
00189 monotonic_warning = true;
00190 }
00191
00192 prev_time = t;
00193 }
00194
00195 int index = 0;
00196 for (int i=0; i < string_items.size(); i++ )
00197 {
00198 bool is_number = false;
00199 double y = string_items[i].toDouble(&is_number);
00200 if( is_number )
00201 {
00202 PlotData::Point point( t,y );
00203 plots_vector[index]->pushBack( point );
00204 }
00205 index++;
00206 }
00207
00208 if(linecount++ %100 == 0)
00209 {
00210 progress_dialog.setValue( linecount );
00211 QApplication::processEvents();
00212 if( progress_dialog.wasCanceled() ) {
00213 interrupted = true;
00214 break;
00215 }
00216 }
00217 }
00218 file.close();
00219
00220 if(interrupted)
00221 {
00222 progress_dialog.cancel();
00223 plot_data.numeric.clear();
00224 }
00225
00226 if( monotonic_warning )
00227 {
00228 QString message = "Two consecutive samples had the same X value (i.e. time).\n"
00229 "Since PlotJuggler makes the assumption that timeseries are strictly monotonic, you "
00230 "might experience undefined behaviours.\n\n"
00231 "You have been warned...";
00232 QMessageBox::warning(0, tr("Warning"), message );
00233 }
00234
00235 return true;
00236 }
00237
00238 DataLoadCSV::~DataLoadCSV()
00239 {
00240
00241 }
00242
00243 bool DataLoadCSV::xmlSaveState(QDomDocument &doc, QDomElement &parent_element) const
00244 {
00245 QDomElement elem = doc.createElement("default");
00246 elem.setAttribute("time_axis", _default_time_axis.c_str() );
00247
00248 parent_element.appendChild( elem );
00249 return true;
00250 }
00251
00252 bool DataLoadCSV::xmlLoadState(const QDomElement &parent_element)
00253 {
00254 QDomElement elem = parent_element.firstChildElement( "default" );
00255 if( !elem.isNull() )
00256 {
00257 if( elem.hasAttribute("time_axis") )
00258 {
00259 _default_time_axis = elem.attribute("time_axis").toStdString();
00260 return true;
00261 }
00262 }
00263 return false;
00264 }