John Beard 4c8b971021 Eeschema: Symbol editor: pin table CSV interchange
This adds the ability to export the pin table content to a CSV file
or the clipboard as CSV, then re-import it from CSV or TSV. This allows:

* to round-trip pin table data via a spreadsheet program, so that the pin
  data can be manipulated in a richer/more familiar editing environment
* an import method to bring in tabular pin data from other formats
  "semi-automatically", without having to write a full-blown symbol generator.

Relates-To: https://gitlab.com/kicad/code/kicad/-/issues/19207
2025-05-03 23:22:35 +08:00

99 lines
2.4 KiB
C++

#include "csv.h"
#include <wx/txtstrm.h>
#include <rapidcsv/rapidcsv.h>
CSV_WRITER::CSV_WRITER( wxOutputStream& aStream ) :
m_stream( aStream ), m_delimiter( wxT( "," ) ), m_quote( wxT( "\"" ) ), m_lineTerminator( wxT( "\n" ) ),
m_escape( wxEmptyString )
{
}
void CSV_WRITER::WriteLines( const std::vector<std::vector<wxString>>& aRows )
{
for( const auto& row : aRows )
{
WriteLine( row );
}
}
void CSV_WRITER::WriteLine( const std::vector<wxString>& cols )
{
wxString line;
for( size_t i = 0; i < cols.size(); ++i )
{
wxString colVal = cols[i];
if( i > 0 )
line += m_delimiter;
double test;
if( !colVal.ToDouble( &test ) )
{
bool useEscape = m_escape.size();
if( useEscape )
{
colVal.Replace( m_quote, m_escape + m_quote, true );
}
else
{
colVal.Replace( m_quote, m_quote + m_quote, true );
}
colVal = m_quote + colVal + m_quote;
}
line += colVal;
}
line += m_lineTerminator;
m_stream.Write( line.c_str(), line.length() );
}
bool AutoDecodeCSV( const wxString& aInput, std::vector<std::vector<wxString>>& aData )
{
// Read the first line to determine the delimiter
bool trimCells = true;
bool skipCommentLines = true;
bool skipEmptyLines = true;
char commentPrefix = '#';
char delimiter = ',';
// Assume if we find a tab, we are dealing with a TSV file
if( aInput.find( '\t' ) != std::string::npos )
{
delimiter = '\t';
}
std::istringstream inputStream( aInput.ToStdString() );
rapidcsv::Document doc( inputStream, rapidcsv::LabelParams( -1, -1 ),
rapidcsv::SeparatorParams( delimiter, trimCells ), rapidcsv::ConverterParams(),
rapidcsv::LineReaderParams( skipCommentLines, commentPrefix, skipEmptyLines ) );
// Read the data into aData
aData.clear();
for( size_t i = 0; i < doc.GetRowCount(); ++i )
{
std::vector<wxString>& row = aData.emplace_back();
for( size_t j = 0; j < doc.GetColumnCount(); ++j )
{
std::string cell = doc.GetCell<std::string>( j, i );
row.emplace_back( cell );
}
}
// Anything in the first row?
return aData[0].size() > 0;
}