ODB++:Support choice compress format and specify output filename.

This commit is contained in:
Eric Zhuang 2024-12-29 17:01:27 +00:00
parent 659228de2d
commit b3259a1c42
12 changed files with 393 additions and 157 deletions

View File

@ -32,6 +32,7 @@ NLOHMANN_JSON_SERIALIZE_ENUM( JOB_EXPORT_PCB_ODB::ODB_COMPRESSION,
{ {
{ JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::NONE, "none" }, { JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::NONE, "none" },
{ JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::ZIP, "zip" }, { JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::ZIP, "zip" },
{ JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::TGZ, "tgz" },
} ) } )

View File

@ -42,6 +42,7 @@ public:
{ {
NONE, NONE,
ZIP, ZIP,
TGZ,
}; };
wxString m_filename; wxString m_filename;

View File

@ -49,7 +49,7 @@ CLI::PCB_EXPORT_ODB_COMMAND::PCB_EXPORT_ODB_COMMAND() :
m_argParser.add_argument( ARG_COMPRESS ) m_argParser.add_argument( ARG_COMPRESS )
.default_value( std::string( "zip" ) ) .default_value( std::string( "zip" ) )
.help( std::string( "Compression mode" ) ) .help( std::string( "Compression mode" ) )
.choices( "none", "zip" ); .choices( "none", "zip", "tgz" );
m_argParser.add_argument( ARG_UNITS ) m_argParser.add_argument( ARG_UNITS )
.default_value( std::string( "mm" ) ) .default_value( std::string( "mm" ) )
@ -87,11 +87,13 @@ int CLI::PCB_EXPORT_ODB_COMMAND::doPerform( KIWAY& aKiway )
else if( units == "in" ) else if( units == "in" )
job->m_units = JOB_EXPORT_PCB_ODB::ODB_UNITS::INCHES; job->m_units = JOB_EXPORT_PCB_ODB::ODB_UNITS::INCHES;
wxString compression = From_UTF8( m_argParser.get<std::string>( ARG_COMPRESS ).c_str() ); wxString compression = From_UTF8( m_argParser.get<std::string>( ARG_COMPRESS ).c_str() ).Lower();
if( compression == "zip" ) if( compression == "zip" )
job->m_compressionMode = JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::ZIP; job->m_compressionMode = JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::ZIP;
else else if( compression == "tgz" )
job->m_compressionMode = JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::TGZ;
else if( compression == "none" )
job->m_compressionMode = JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::NONE; job->m_compressionMode = JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::NONE;
LOCALE_IO dummy; LOCALE_IO dummy;

View File

@ -42,16 +42,16 @@
#include <jobs/job_export_pcb_odb.h> #include <jobs/job_export_pcb_odb.h>
#include <pcb_io/pcb_io_mgr.h> #include <pcb_io/pcb_io_mgr.h>
#include <wx/dir.h> #include <wx/dir.h>
#include <wx/dirdlg.h> #include <wx/filedlg.h>
#include <wx/wfstream.h> #include <wx/wfstream.h>
#include <wx/zipstrm.h> #include <wx/zipstrm.h>
#include <wx/tarstrm.h>
#include <wx/zstream.h>
static wxString s_oemColumn = wxEmptyString; static wxString s_oemColumn = wxEmptyString;
DIALOG_EXPORT_ODBPP::DIALOG_EXPORT_ODBPP( PCB_EDIT_FRAME* aParent ) : DIALOG_EXPORT_ODBPP::DIALOG_EXPORT_ODBPP( PCB_EDIT_FRAME* aParent ) :
DIALOG_EXPORT_ODBPP_BASE( aParent ), DIALOG_EXPORT_ODBPP_BASE( aParent ), m_parent( aParent ), m_job( nullptr )
m_parent( aParent ),
m_job( nullptr )
{ {
m_browseButton->SetBitmap( KiBitmapBundle( BITMAPS::small_folder ) ); m_browseButton->SetBitmap( KiBitmapBundle( BITMAPS::small_folder ) );
@ -62,7 +62,10 @@ DIALOG_EXPORT_ODBPP::DIALOG_EXPORT_ODBPP( PCB_EDIT_FRAME* aParent ) :
if( path.IsEmpty() ) if( path.IsEmpty() )
{ {
wxFileName brdFile( m_parent->GetBoard()->GetFileName() ); wxFileName brdFile( m_parent->GetBoard()->GetFileName() );
path = brdFile.GetPath(); wxFileName odbFile( brdFile.GetPath(),
wxString::Format( wxS( "%s-odb" ), brdFile.GetName() ),
FILEEXT::ArchiveFileExtension );
path = odbFile.GetFullPath();
} }
m_outputFileName->SetValue( path ); m_outputFileName->SetValue( path );
@ -78,9 +81,7 @@ DIALOG_EXPORT_ODBPP::DIALOG_EXPORT_ODBPP( PCB_EDIT_FRAME* aParent ) :
DIALOG_EXPORT_ODBPP::DIALOG_EXPORT_ODBPP( JOB_EXPORT_PCB_ODB* aJob, PCB_EDIT_FRAME* aEditFrame, DIALOG_EXPORT_ODBPP::DIALOG_EXPORT_ODBPP( JOB_EXPORT_PCB_ODB* aJob, PCB_EDIT_FRAME* aEditFrame,
wxWindow* aParent ) : wxWindow* aParent ) :
DIALOG_EXPORT_ODBPP_BASE( aParent ), DIALOG_EXPORT_ODBPP_BASE( aParent ), m_parent( aEditFrame ), m_job( aJob )
m_parent( aEditFrame ),
m_job( aJob )
{ {
m_browseButton->Hide(); m_browseButton->Hide();
@ -99,23 +100,128 @@ DIALOG_EXPORT_ODBPP::DIALOG_EXPORT_ODBPP( JOB_EXPORT_PCB_ODB* aJob, PCB_EDIT_FRA
void DIALOG_EXPORT_ODBPP::onBrowseClicked( wxCommandEvent& event ) void DIALOG_EXPORT_ODBPP::onBrowseClicked( wxCommandEvent& event )
{ {
// clang-format off
wxString filter = _( "zip files" )
+ AddFileExtListToFilter( { FILEEXT::ArchiveFileExtension } ) + "|"
+ _( "tgz files" )
+ AddFileExtListToFilter( { "tgz" } );
// clang-format on
// Build the absolute path of current output directory to preselect it in the file browser. // Build the absolute path of current output directory to preselect it in the file browser.
wxString path = ExpandEnvVarSubstitutions( m_outputFileName->GetValue(), &Prj() ); wxString path = ExpandEnvVarSubstitutions( m_outputFileName->GetValue(), &Prj() );
wxFileName fn( Prj().AbsolutePath( path ) ); wxFileName fn( Prj().AbsolutePath( path ) );
wxDirDialog dlg( this, _( "Export ODB++ File" ), fn.GetPath() ); wxFileName brdFile( m_parent->GetBoard()->GetFileName() );
wxString fileDialogName( wxString::Format( wxS( "%s-odb" ), brdFile.GetName() ) );
wxFileDialog dlg( this, _( "Export ODB++ File" ), fn.GetPath(), fileDialogName, filter,
wxFD_SAVE );
if( dlg.ShowModal() == wxID_CANCEL ) if( dlg.ShowModal() == wxID_CANCEL )
return; return;
m_outputFileName->SetValue( dlg.GetPath() ); path = dlg.GetPath();
fn = wxFileName( path );
if( fn.GetExt().Lower() == "zip" )
{
m_choiceCompress->SetSelection(
static_cast<int>( JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::ZIP ) );
}
else if( fn.GetExt().Lower() == "tgz" )
{
m_choiceCompress->SetSelection(
static_cast<int>( JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::TGZ ) );
}
else if( path.EndsWith( "/" ) || path.EndsWith( "\\" ) )
{
m_choiceCompress->SetSelection(
static_cast<int>( JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::NONE ) );
}
else
{
wxString msg;
msg.Printf( _( "The selected output file name is not a supported archive format." ) );
DisplayErrorMessage( this, msg );
return;
}
m_outputFileName->SetValue( path );
} }
void DIALOG_EXPORT_ODBPP::onFormatChoice( wxCommandEvent& event )
{
OnFmtChoiceOptionChanged();
}
void DIALOG_EXPORT_ODBPP::OnFmtChoiceOptionChanged()
{
wxString fn = m_outputFileName->GetValue();
wxFileName fileName( fn );
auto compressionMode =
static_cast<JOB_EXPORT_PCB_ODB::ODB_COMPRESSION>( m_choiceCompress->GetSelection() );
int sepIdx = std::max( fn.Find( '/', true ), fn.Find( '\\', true ) );
int dotIdx = fn.Find( '.', true );
if( fileName.IsDir() )
fn = fn.Mid( 0, sepIdx );
else if( sepIdx < dotIdx )
fn = fn.Mid( 0, dotIdx );
switch( compressionMode )
{
case JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::ZIP:
fn = fn + '.' + FILEEXT::ArchiveFileExtension;
break;
case JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::TGZ: fn += ".tgz"; break;
case JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::NONE: fn = wxFileName( fn, "" ).GetFullPath(); break;
default: break;
};
m_outputFileName->SetValue( fn );
}
void DIALOG_EXPORT_ODBPP::onOKClick( wxCommandEvent& event ) void DIALOG_EXPORT_ODBPP::onOKClick( wxCommandEvent& event )
{ {
if( !m_job ) if( !m_job )
{
wxString fn = m_outputFileName->GetValue();
if( fn.IsEmpty() )
{
wxString msg;
msg.Printf( _( "Output file name cannot be empty." ) );
DisplayErrorMessage( this, msg );
return;
}
auto compressionMode = static_cast<JOB_EXPORT_PCB_ODB::ODB_COMPRESSION>(
m_choiceCompress->GetSelection() );
wxFileName fileName( fn );
bool isDirectory = fileName.IsDir();
wxString extension = fileName.GetExt();
if( ( compressionMode == JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::NONE && !isDirectory )
|| ( compressionMode == JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::ZIP && extension != "zip" )
|| ( compressionMode == JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::TGZ
&& extension != "tgz" ) )
{
wxString msg;
msg.Printf(
_( "The output file name conflicts with the selected compression format." ) );
DisplayErrorMessage( this, msg );
return;
}
m_parent->SetLastPath( LAST_PATH_ODBPP, m_outputFileName->GetValue() ); m_parent->SetLastPath( LAST_PATH_ODBPP, m_outputFileName->GetValue() );
}
event.Skip(); event.Skip();
} }
@ -130,13 +236,13 @@ bool DIALOG_EXPORT_ODBPP::Init()
{ {
m_choiceUnits->SetSelection( cfg->m_ExportODBPP.units ); m_choiceUnits->SetSelection( cfg->m_ExportODBPP.units );
m_precision->SetValue( cfg->m_ExportODBPP.precision ); m_precision->SetValue( cfg->m_ExportODBPP.precision );
m_cbCompress->SetValue( cfg->m_ExportODBPP.compress ); m_choiceCompress->SetSelection( cfg->m_ExportODBPP.compressFormat );
} }
else else
{ {
m_choiceUnits->SetSelection( static_cast<int>( m_job->m_units ) ); m_choiceUnits->SetSelection( static_cast<int>( m_job->m_units ) );
m_precision->SetValue( m_job->m_precision ); m_precision->SetValue( m_job->m_precision );
m_cbCompress->SetValue( m_job->m_compressionMode == JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::ZIP ); m_choiceCompress->SetSelection( static_cast<int>( m_job->m_compressionMode ) );
} }
return true; return true;
@ -152,17 +258,17 @@ bool DIALOG_EXPORT_ODBPP::TransferDataFromWindow()
cfg->m_ExportODBPP.units = m_choiceUnits->GetSelection(); cfg->m_ExportODBPP.units = m_choiceUnits->GetSelection();
cfg->m_ExportODBPP.precision = m_precision->GetValue(); cfg->m_ExportODBPP.precision = m_precision->GetValue();
cfg->m_ExportODBPP.compress = m_cbCompress->GetValue(); cfg->m_ExportODBPP.compressFormat = m_choiceCompress->GetSelection();
} }
else else
{ {
m_job->SetOutputPath( m_outputFileName->GetValue() ); m_job->SetOutputPath( m_outputFileName->GetValue() );
m_job->m_precision = m_precision->GetValue(); m_job->m_precision = m_precision->GetValue();
m_job->m_units = static_cast<JOB_EXPORT_PCB_ODB::ODB_UNITS>( m_choiceUnits->GetSelection() ); m_job->m_units =
m_job->m_compressionMode = m_cbCompress->GetValue() static_cast<JOB_EXPORT_PCB_ODB::ODB_UNITS>( m_choiceUnits->GetSelection() );
? JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::ZIP m_job->m_compressionMode = static_cast<JOB_EXPORT_PCB_ODB::ODB_COMPRESSION>(
: JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::NONE; m_choiceCompress->GetSelection() );
} }
return true; return true;
@ -170,9 +276,9 @@ bool DIALOG_EXPORT_ODBPP::TransferDataFromWindow()
void DIALOG_EXPORT_ODBPP::GenerateODBPPFiles( const JOB_EXPORT_PCB_ODB& aJob, BOARD* aBoard, void DIALOG_EXPORT_ODBPP::GenerateODBPPFiles( const JOB_EXPORT_PCB_ODB& aJob, BOARD* aBoard,
PCB_EDIT_FRAME* aParentFrame, PCB_EDIT_FRAME* aParentFrame,
PROGRESS_REPORTER* aProgressReporter, PROGRESS_REPORTER* aProgressReporter,
REPORTER* aReporter ) REPORTER* aReporter )
{ {
wxCHECK( aBoard, /* void */ ); wxCHECK( aBoard, /* void */ );
wxString outputPath = aJob.GetOutputPath(); wxString outputPath = aJob.GetOutputPath();
@ -190,6 +296,20 @@ void DIALOG_EXPORT_ODBPP::GenerateODBPPFiles( const JOB_EXPORT_PCB_ODB& aJob, BO
wxString msg; wxString msg;
if( !wxFileName::DirExists( pcbFileName.GetPath() ) )
{
// Make every directory provided when the provided path doesn't exist
if( !wxFileName::Mkdir( pcbFileName.GetPath(), wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) )
{
msg.Printf( _( "Cannot create output directory '%s'." ), pcbFileName.GetFullPath() );
if( aReporter )
aReporter->Report( msg, RPT_SEVERITY_ERROR );
return;
}
}
if( pcbFileName.IsDir() && !pcbFileName.IsDirWritable() ) if( pcbFileName.IsDir() && !pcbFileName.IsDirWritable() )
{ {
msg.Printf( _( "Insufficient permissions to folder '%s'." ), pcbFileName.GetPath() ); msg.Printf( _( "Insufficient permissions to folder '%s'." ), pcbFileName.GetPath() );
@ -211,35 +331,17 @@ void DIALOG_EXPORT_ODBPP::GenerateODBPPFiles( const JOB_EXPORT_PCB_ODB& aJob, BO
return; return;
} }
if( !wxFileName::DirExists( pcbFileName.GetFullPath() ) ) wxFileName tempFile( pcbFileName.GetFullPath() );
{
// Make every directory provided when the provided path doesn't exist
if( !wxFileName::Mkdir( pcbFileName.GetFullPath(), wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) )
{
msg.Printf( _( "Cannot create output directory '%s'." ), pcbFileName.GetFullPath() );
if( aReporter )
aReporter->Report( msg, RPT_SEVERITY_ERROR );
return;
}
}
wxFileName zipFileName( pcbFileName.GetFullPath(),
wxString::Format( wxS( "%s-odb.zip" ),
aBoard->GetProject()->GetProjectName() ) );
wxFileName tempFile( pcbFileName.GetFullPath(), "" );
if( aJob.m_compressionMode != JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::NONE ) if( aJob.m_compressionMode != JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::NONE )
{ {
if( zipFileName.Exists() ) if( pcbFileName.Exists() )
{ {
if( aParentFrame ) if( aParentFrame )
{ {
msg = wxString::Format( _( "Output files '%s' already exists. " msg = wxString::Format( _( "Output files '%s' already exists. "
"Do you want to overwrite it?" ), "Do you want to overwrite it?" ),
zipFileName.GetFullPath() ); pcbFileName.GetFullPath() );
KIDIALOG errorDlg( aParentFrame, msg, _( "Confirmation" ), KIDIALOG errorDlg( aParentFrame, msg, _( "Confirmation" ),
wxOK | wxCANCEL | wxICON_WARNING ); wxOK | wxCANCEL | wxICON_WARNING );
@ -248,10 +350,10 @@ void DIALOG_EXPORT_ODBPP::GenerateODBPPFiles( const JOB_EXPORT_PCB_ODB& aJob, BO
if( errorDlg.ShowModal() != wxID_OK ) if( errorDlg.ShowModal() != wxID_OK )
return; return;
if( !wxRemoveFile( zipFileName.GetFullPath() ) ) if( !wxRemoveFile( pcbFileName.GetFullPath() ) )
{ {
msg.Printf( _( "Cannot remove existing output file '%s'." ), msg.Printf( _( "Cannot remove existing output file '%s'." ),
zipFileName.GetFullPath() ); pcbFileName.GetFullPath() );
DisplayErrorMessage( aParentFrame, msg ); DisplayErrorMessage( aParentFrame, msg );
return; return;
} }
@ -259,7 +361,7 @@ void DIALOG_EXPORT_ODBPP::GenerateODBPPFiles( const JOB_EXPORT_PCB_ODB& aJob, BO
else else
{ {
msg = wxString::Format( _( "Output file '%s' already exists." ), msg = wxString::Format( _( "Output file '%s' already exists." ),
zipFileName.GetFullPath() ); pcbFileName.GetFullPath() );
if( aReporter ) if( aReporter )
aReporter->Report( msg, RPT_SEVERITY_ERROR ); aReporter->Report( msg, RPT_SEVERITY_ERROR );
@ -284,10 +386,8 @@ void DIALOG_EXPORT_ODBPP::GenerateODBPPFiles( const JOB_EXPORT_PCB_ODB& aJob, BO
} }
else else
{ {
// Plugin will create the 'odb' subdirectory for us, so test for it here // Test for the output directory of tempFile
wxFileName odbDir( tempFile ); wxDir testDir( tempFile.GetFullPath() );
odbDir.AppendDir( "odb" );
wxDir testDir( odbDir.GetFullPath() );
if( testDir.IsOpened() && ( testDir.HasFiles() || testDir.HasSubDirs() ) ) if( testDir.IsOpened() && ( testDir.HasFiles() || testDir.HasSubDirs() ) )
{ {
@ -295,7 +395,7 @@ void DIALOG_EXPORT_ODBPP::GenerateODBPPFiles( const JOB_EXPORT_PCB_ODB& aJob, BO
{ {
msg = wxString::Format( _( "Output directory '%s' already exists and is not empty. " msg = wxString::Format( _( "Output directory '%s' already exists and is not empty. "
"Do you want to overwrite it?" ), "Do you want to overwrite it?" ),
odbDir.GetFullPath() ); tempFile.GetFullPath() );
KIDIALOG errorDlg( aParentFrame, msg, _( "Confirmation" ), KIDIALOG errorDlg( aParentFrame, msg, _( "Confirmation" ),
wxOK | wxCANCEL | wxICON_WARNING ); wxOK | wxCANCEL | wxICON_WARNING );
@ -304,10 +404,10 @@ void DIALOG_EXPORT_ODBPP::GenerateODBPPFiles( const JOB_EXPORT_PCB_ODB& aJob, BO
if( errorDlg.ShowModal() != wxID_OK ) if( errorDlg.ShowModal() != wxID_OK )
return; return;
if( !odbDir.Rmdir( wxPATH_RMDIR_RECURSIVE ) ) if( !tempFile.Rmdir( wxPATH_RMDIR_RECURSIVE ) )
{ {
msg.Printf( _( "Cannot remove existing output directory '%s'." ), msg.Printf( _( "Cannot remove existing output directory '%s'." ),
odbDir.GetFullPath() ); tempFile.GetFullPath() );
DisplayErrorMessage( aParentFrame, msg ); DisplayErrorMessage( aParentFrame, msg );
return; return;
} }
@ -315,7 +415,7 @@ void DIALOG_EXPORT_ODBPP::GenerateODBPPFiles( const JOB_EXPORT_PCB_ODB& aJob, BO
else else
{ {
msg = wxString::Format( _( "Output directory '%s' already exists." ), msg = wxString::Format( _( "Output directory '%s' already exists." ),
odbDir.GetFullPath() ); tempFile.GetFullPath() );
if( aReporter ) if( aReporter )
aReporter->Report( msg, RPT_SEVERITY_ERROR ); aReporter->Report( msg, RPT_SEVERITY_ERROR );
@ -332,31 +432,30 @@ void DIALOG_EXPORT_ODBPP::GenerateODBPPFiles( const JOB_EXPORT_PCB_ODB& aJob, BO
props["units"] = aJob.m_units == JOB_EXPORT_PCB_ODB::ODB_UNITS::MILLIMETERS ? "mm" : "inch"; props["units"] = aJob.m_units == JOB_EXPORT_PCB_ODB::ODB_UNITS::MILLIMETERS ? "mm" : "inch";
props["sigfig"] = wxString::Format( "%d", aJob.m_precision ); props["sigfig"] = wxString::Format( "%d", aJob.m_precision );
auto saveFile = auto saveFile = [&]() -> bool
[&]() -> bool {
try
{
IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::PluginFind( PCB_IO_MGR::ODBPP ) );
pi->SetReporter( aReporter );
pi->SetProgressReporter( aProgressReporter );
pi->SaveBoard( tempFile.GetFullPath(), aBoard, &props );
return true;
}
catch( const IO_ERROR& ioe )
{
if( aReporter )
{ {
try msg = wxString::Format( _( "Error generating ODBPP files '%s'.\n%s" ),
{ tempFile.GetFullPath(), ioe.What() );
IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::PluginFind( PCB_IO_MGR::ODBPP ) ); aReporter->Report( msg, RPT_SEVERITY_ERROR );
pi->SetReporter( aReporter ); }
pi->SetProgressReporter( aProgressReporter );
pi->SaveBoard( tempFile.GetFullPath(), aBoard, &props );
return true;
}
catch( const IO_ERROR& ioe )
{
if( aReporter )
{
msg = wxString::Format( _( "Error generating ODBPP files '%s'.\n%s" ),
tempFile.GetFullPath(), ioe.What() );
aReporter->Report( msg, RPT_SEVERITY_ERROR );
}
// In case we started a file but didn't fully write it, clean up // In case we started a file but didn't fully write it, clean up
wxFileName::Rmdir( tempFile.GetFullPath() ); wxFileName::Rmdir( tempFile.GetFullPath() );
return false; return false;
} }
}; };
thread_pool& tp = GetKiCadThreadPool(); thread_pool& tp = GetKiCadThreadPool();
auto ret = tp.submit( saveFile ); auto ret = tp.submit( saveFile );
@ -365,7 +464,7 @@ void DIALOG_EXPORT_ODBPP::GenerateODBPPFiles( const JOB_EXPORT_PCB_ODB& aJob, BO
while( status != std::future_status::ready ) while( status != std::future_status::ready )
{ {
if( aProgressReporter) if( aProgressReporter )
aProgressReporter->KeepRefreshing(); aProgressReporter->KeepRefreshing();
status = ret.wait_for( std::chrono::milliseconds( 250 ) ); status = ret.wait_for( std::chrono::milliseconds( 250 ) );
@ -387,12 +486,12 @@ void DIALOG_EXPORT_ODBPP::GenerateODBPPFiles( const JOB_EXPORT_PCB_ODB& aJob, BO
return; return;
} }
if( aJob.m_compressionMode != JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::NONE ) if( aJob.m_compressionMode == JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::ZIP )
{ {
if( aProgressReporter ) if( aProgressReporter )
aProgressReporter->AdvancePhase( _( "Compressing output" ) ); aProgressReporter->AdvancePhase( _( "Compressing output" ) );
wxFFileOutputStream fnout( zipFileName.GetFullPath() ); wxFFileOutputStream fnout( pcbFileName.GetFullPath() );
wxZipOutputStream zipStream( fnout ); wxZipOutputStream zipStream( fnout );
std::function<void( const wxString&, const wxString& )> addDirToZip = std::function<void( const wxString&, const wxString& )> addDirToZip =
@ -434,6 +533,54 @@ void DIALOG_EXPORT_ODBPP::GenerateODBPPFiles( const JOB_EXPORT_PCB_ODB& aJob, BO
tempFile.Rmdir( wxPATH_RMDIR_RECURSIVE ); tempFile.Rmdir( wxPATH_RMDIR_RECURSIVE );
} }
else if( aJob.m_compressionMode == JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::TGZ )
{
wxFFileOutputStream fnout( pcbFileName.GetFullPath() );
wxZlibOutputStream zlibStream( fnout, -1, wxZLIB_GZIP );
wxTarOutputStream tarStream( zlibStream );
std::function<void( const wxString&, const wxString& )> addDirToTar =
[&]( const wxString& dirPath, const wxString& parentPath )
{
wxDir dir( dirPath );
wxString fileName;
bool cont = dir.GetFirst( &fileName, wxEmptyString, wxDIR_DEFAULT );
while( cont )
{
wxFileName fileInTar( dirPath, fileName );
wxString relativePath =
parentPath.IsEmpty()
? fileName
: parentPath + wxString( wxFileName::GetPathSeparator() )
+ fileName;
if( wxFileName::DirExists( fileInTar.GetFullPath() ) )
{
tarStream.PutNextDirEntry( relativePath );
addDirToTar( fileInTar.GetFullPath(), relativePath );
}
else
{
wxFFileInputStream fileStream( fileInTar.GetFullPath() );
tarStream.PutNextEntry( relativePath, wxDateTime::Now(),
fileStream.GetLength() );
fileStream.Read( tarStream );
}
cont = dir.GetNext( &fileName );
}
};
addDirToTar(
tempFile.GetFullPath(),
tempFile.GetPath( wxPATH_NO_SEPARATOR ).AfterLast( tempFile.GetPathSeparator() ) );
tarStream.Close();
zlibStream.Close();
fnout.Close();
tempFile.Rmdir( wxPATH_RMDIR_RECURSIVE );
}
if( aProgressReporter ) if( aProgressReporter )
aProgressReporter->SetCurrentProgress( 1 ); aProgressReporter->SetCurrentProgress( 1 );

View File

@ -47,10 +47,10 @@
<property name="hidden">0</property> <property name="hidden">0</property>
<property name="id">wxID_ANY</property> <property name="id">wxID_ANY</property>
<property name="maximum_size"></property> <property name="maximum_size"></property>
<property name="minimum_size"></property> <property name="minimum_size">380,265</property>
<property name="name">DIALOG_EXPORT_ODBPP_BASE</property> <property name="name">DIALOG_EXPORT_ODBPP_BASE</property>
<property name="pos"></property> <property name="pos"></property>
<property name="size">380,300</property> <property name="size">-1,-1</property>
<property name="style">wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</property> <property name="style">wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</property>
<property name="subclass">DIALOG_SHIM; dialog_shim.h</property> <property name="subclass">DIALOG_SHIM; dialog_shim.h</property>
<property name="title">Export ODB++</property> <property name="title">Export ODB++</property>
@ -58,15 +58,15 @@
<property name="two_step_creation">0</property> <property name="two_step_creation">0</property>
<property name="window_extra_style"></property> <property name="window_extra_style"></property>
<property name="window_name"></property> <property name="window_name"></property>
<property name="window_style"></property> <property name="window_style">wxBORDER_DEFAULT</property>
<object class="wxBoxSizer" expanded="true"> <object class="wxBoxSizer" expanded="true">
<property name="minimum_size"></property> <property name="minimum_size"></property>
<property name="name">bMainSizer</property> <property name="name">bMainSizer</property>
<property name="orient">wxVERTICAL</property> <property name="orient">wxVERTICAL</property>
<property name="permission">none</property> <property name="permission">none</property>
<object class="sizeritem" expanded="true"> <object class="sizeritem" expanded="true">
<property name="border">15</property> <property name="border">5</property>
<property name="flag">wxBOTTOM|wxEXPAND|wxTOP</property> <property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxBoxSizer" expanded="true"> <object class="wxBoxSizer" expanded="true">
<property name="minimum_size"></property> <property name="minimum_size"></property>
@ -75,7 +75,7 @@
<property name="permission">protected</property> <property name="permission">protected</property>
<object class="sizeritem" expanded="false"> <object class="sizeritem" expanded="false">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT</property> <property name="flag">wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxStaticText" expanded="false"> <object class="wxStaticText" expanded="false">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
@ -106,7 +106,7 @@
<property name="gripper">0</property> <property name="gripper">0</property>
<property name="hidden">0</property> <property name="hidden">0</property>
<property name="id">wxID_ANY</property> <property name="id">wxID_ANY</property>
<property name="label">Folder:</property> <property name="label">Output File:</property>
<property name="markup">0</property> <property name="markup">0</property>
<property name="max_size"></property> <property name="max_size"></property>
<property name="maximize_button">0</property> <property name="maximize_button">0</property>
@ -137,7 +137,7 @@
</object> </object>
<object class="sizeritem" expanded="false"> <object class="sizeritem" expanded="false">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL</property> <property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">1</property> <property name="proportion">1</property>
<object class="wxTextCtrl" expanded="false"> <object class="wxTextCtrl" expanded="false">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
@ -278,7 +278,7 @@
</object> </object>
</object> </object>
<object class="sizeritem" expanded="true"> <object class="sizeritem" expanded="true">
<property name="border">5</property> <property name="border">10</property>
<property name="flag">wxEXPAND</property> <property name="flag">wxEXPAND</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxBoxSizer" expanded="true"> <object class="wxBoxSizer" expanded="true">
@ -286,11 +286,11 @@
<property name="name">bSizer3</property> <property name="name">bSizer3</property>
<property name="orient">wxHORIZONTAL</property> <property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property> <property name="permission">none</property>
<object class="sizeritem" expanded="true"> <object class="sizeritem" expanded="false">
<property name="border">10</property> <property name="border">10</property>
<property name="flag">wxEXPAND|wxLEFT|wxRIGHT|wxTOP</property> <property name="flag">wxEXPAND|wxALL</property>
<property name="proportion">1</property> <property name="proportion">1</property>
<object class="wxStaticBoxSizer" expanded="true"> <object class="wxStaticBoxSizer" expanded="false">
<property name="id">wxID_ANY</property> <property name="id">wxID_ANY</property>
<property name="label">File Format</property> <property name="label">File Format</property>
<property name="minimum_size"></property> <property name="minimum_size"></property>
@ -300,12 +300,12 @@
<property name="permission">none</property> <property name="permission">none</property>
<object class="sizeritem" expanded="false"> <object class="sizeritem" expanded="false">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxEXPAND|wxALL</property> <property name="flag">wxEXPAND|wxLEFT</property>
<property name="proportion">3</property> <property name="proportion">3</property>
<object class="wxFlexGridSizer" expanded="false"> <object class="wxFlexGridSizer" expanded="false">
<property name="cols">2</property> <property name="cols">2</property>
<property name="flexible_direction">wxBOTH</property> <property name="flexible_direction">wxBOTH</property>
<property name="growablecols">1</property> <property name="growablecols">0,1</property>
<property name="growablerows"></property> <property name="growablerows"></property>
<property name="hgap">0</property> <property name="hgap">0</property>
<property name="minimum_size"></property> <property name="minimum_size"></property>
@ -316,7 +316,7 @@
<property name="vgap">0</property> <property name="vgap">0</property>
<object class="sizeritem" expanded="false"> <object class="sizeritem" expanded="false">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxALL|wxALIGN_CENTER_VERTICAL</property> <property name="flag">wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxStaticText" expanded="false"> <object class="wxStaticText" expanded="false">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
@ -378,7 +378,7 @@
</object> </object>
<object class="sizeritem" expanded="false"> <object class="sizeritem" expanded="false">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxALIGN_RIGHT|wxALL</property> <property name="flag">wxEXPAND|wxALL</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxChoice" expanded="false"> <object class="wxChoice" expanded="false">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
@ -415,7 +415,7 @@
<property name="maximum_size"></property> <property name="maximum_size"></property>
<property name="min_size"></property> <property name="min_size"></property>
<property name="minimize_button">0</property> <property name="minimize_button">0</property>
<property name="minimum_size"></property> <property name="minimum_size">-1,-1</property>
<property name="moveable">1</property> <property name="moveable">1</property>
<property name="name">m_choiceUnits</property> <property name="name">m_choiceUnits</property>
<property name="pane_border">1</property> <property name="pane_border">1</property>
@ -427,7 +427,7 @@
<property name="resize">Resizable</property> <property name="resize">Resizable</property>
<property name="selection">0</property> <property name="selection">0</property>
<property name="show">1</property> <property name="show">1</property>
<property name="size">130,30</property> <property name="size">-1,-1</property>
<property name="style"></property> <property name="style"></property>
<property name="subclass">; ; forward_declare</property> <property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property> <property name="toolbar_pane">0</property>
@ -443,7 +443,7 @@
</object> </object>
<object class="sizeritem" expanded="false"> <object class="sizeritem" expanded="false">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxALL|wxALIGN_CENTER_VERTICAL</property> <property name="flag">wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxStaticText" expanded="false"> <object class="wxStaticText" expanded="false">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
@ -505,7 +505,7 @@
</object> </object>
<object class="sizeritem" expanded="false"> <object class="sizeritem" expanded="false">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxALIGN_RIGHT|wxALL</property> <property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxSpinCtrl" expanded="false"> <object class="wxSpinCtrl" expanded="false">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
@ -536,7 +536,7 @@
<property name="gripper">0</property> <property name="gripper">0</property>
<property name="hidden">0</property> <property name="hidden">0</property>
<property name="id">wxID_ANY</property> <property name="id">wxID_ANY</property>
<property name="initial">7</property> <property name="initial">6</property>
<property name="max">16</property> <property name="max">16</property>
<property name="max_size"></property> <property name="max_size"></property>
<property name="maximize_button">0</property> <property name="maximize_button">0</property>
@ -555,7 +555,7 @@
<property name="pos"></property> <property name="pos"></property>
<property name="resize">Resizable</property> <property name="resize">Resizable</property>
<property name="show">1</property> <property name="show">1</property>
<property name="size">130,30</property> <property name="size">-1,-1</property>
<property name="style">wxSP_ARROW_KEYS</property> <property name="style">wxSP_ARROW_KEYS</property>
<property name="subclass"></property> <property name="subclass"></property>
<property name="toolbar_pane">0</property> <property name="toolbar_pane">0</property>
@ -568,9 +568,9 @@
</object> </object>
<object class="sizeritem" expanded="false"> <object class="sizeritem" expanded="false">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxALL|wxEXPAND</property> <property name="flag">wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxCheckBox" expanded="false"> <object class="wxStaticText" expanded="false">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
<property name="LeftDockable">1</property> <property name="LeftDockable">1</property>
<property name="RightDockable">1</property> <property name="RightDockable">1</property>
@ -584,7 +584,6 @@
<property name="caption"></property> <property name="caption"></property>
<property name="caption_visible">1</property> <property name="caption_visible">1</property>
<property name="center_pane">0</property> <property name="center_pane">0</property>
<property name="checked">0</property>
<property name="close_button">1</property> <property name="close_button">1</property>
<property name="context_help"></property> <property name="context_help"></property>
<property name="context_menu">1</property> <property name="context_menu">1</property>
@ -600,7 +599,8 @@
<property name="gripper">0</property> <property name="gripper">0</property>
<property name="hidden">0</property> <property name="hidden">0</property>
<property name="id">wxID_ANY</property> <property name="id">wxID_ANY</property>
<property name="label">Compress output</property> <property name="label">Compression Format:</property>
<property name="markup">0</property>
<property name="max_size"></property> <property name="max_size"></property>
<property name="maximize_button">0</property> <property name="maximize_button">0</property>
<property name="maximum_size"></property> <property name="maximum_size"></property>
@ -608,7 +608,7 @@
<property name="minimize_button">0</property> <property name="minimize_button">0</property>
<property name="minimum_size"></property> <property name="minimum_size"></property>
<property name="moveable">1</property> <property name="moveable">1</property>
<property name="name">m_cbCompress</property> <property name="name">m_lblCompress</property>
<property name="pane_border">1</property> <property name="pane_border">1</property>
<property name="pane_position"></property> <property name="pane_position"></property>
<property name="pane_size"></property> <property name="pane_size"></property>
@ -619,9 +619,71 @@
<property name="show">1</property> <property name="show">1</property>
<property name="size"></property> <property name="size"></property>
<property name="style"></property> <property name="style"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip">Select the format to compress the output ODB++ files</property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxChoice" expanded="false">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="choices">&quot;None&quot; &quot;ZIP&quot; &quot;TGZ&quot;</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size">-1,-1</property>
<property name="moveable">1</property>
<property name="name">m_choiceCompress</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="selection">1</property>
<property name="show">1</property>
<property name="size">-1,-1</property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property> <property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property> <property name="toolbar_pane">0</property>
<property name="tooltip">Compress output into &apos;zip&apos; file</property> <property name="tooltip"></property>
<property name="validator_data_type"></property> <property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property> <property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property> <property name="validator_type">wxDefaultValidator</property>
@ -629,7 +691,7 @@
<property name="window_extra_style"></property> <property name="window_extra_style"></property>
<property name="window_name"></property> <property name="window_name"></property>
<property name="window_style"></property> <property name="window_style"></property>
<event name="OnCheckBox">onCompressCheck</event> <event name="OnChoice">onFormatChoice</event>
</object> </object>
</object> </object>
</object> </object>
@ -638,16 +700,6 @@
</object> </object>
</object> </object>
</object> </object>
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="spacer" expanded="false">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
<object class="sizeritem" expanded="false"> <object class="sizeritem" expanded="false">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property> <property name="flag">wxALL|wxEXPAND</property>

View File

@ -45,8 +45,7 @@ public:
int GetPrecision() const { return m_precision->GetValue(); } int GetPrecision() const { return m_precision->GetValue(); }
int GetCompressFormat() const { return m_choiceCompress->GetSelection(); }
bool GetCompress() const { return m_cbCompress->GetValue(); }
// Runs the actual generation process; shared between GUI and CLI system // Runs the actual generation process; shared between GUI and CLI system
static void GenerateODBPPFiles( const JOB_EXPORT_PCB_ODB& aJob, BOARD* aBoard, static void GenerateODBPPFiles( const JOB_EXPORT_PCB_ODB& aJob, BOARD* aBoard,
@ -56,8 +55,12 @@ public:
private: private:
void onBrowseClicked( wxCommandEvent& event ) override; void onBrowseClicked( wxCommandEvent& event ) override;
void onFormatChoice( wxCommandEvent& event ) override;
void onOKClick( wxCommandEvent& event ) override; void onOKClick( wxCommandEvent& event ) override;
void OnFmtChoiceOptionChanged();
bool Init(); bool Init();
bool TransferDataFromWindow() override; bool TransferDataFromWindow() override;

View File

@ -13,28 +13,28 @@
DIALOG_EXPORT_ODBPP_BASE::DIALOG_EXPORT_ODBPP_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : DIALOG_SHIM( parent, id, title, pos, size, style ) DIALOG_EXPORT_ODBPP_BASE::DIALOG_EXPORT_ODBPP_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : DIALOG_SHIM( parent, id, title, pos, size, style )
{ {
this->SetSizeHints( wxDefaultSize, wxDefaultSize ); this->SetSizeHints( wxSize( 380,265 ), wxDefaultSize );
wxBoxSizer* bMainSizer; wxBoxSizer* bMainSizer;
bMainSizer = new wxBoxSizer( wxVERTICAL ); bMainSizer = new wxBoxSizer( wxVERTICAL );
bSizerTop = new wxBoxSizer( wxHORIZONTAL ); bSizerTop = new wxBoxSizer( wxHORIZONTAL );
m_lblBrdFile = new wxStaticText( this, wxID_ANY, _("Folder:"), wxDefaultPosition, wxDefaultSize, 0 ); m_lblBrdFile = new wxStaticText( this, wxID_ANY, _("Output File:"), wxDefaultPosition, wxDefaultSize, 0 );
m_lblBrdFile->Wrap( -1 ); m_lblBrdFile->Wrap( -1 );
bSizerTop->Add( m_lblBrdFile, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 ); bSizerTop->Add( m_lblBrdFile, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_outputFileName = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); m_outputFileName = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_outputFileName->SetToolTip( _("Enter a filename if you do not want to use default file names\nCan be used only when printing the current sheet") ); m_outputFileName->SetToolTip( _("Enter a filename if you do not want to use default file names\nCan be used only when printing the current sheet") );
m_outputFileName->SetMinSize( wxSize( 350,-1 ) ); m_outputFileName->SetMinSize( wxSize( 350,-1 ) );
bSizerTop->Add( m_outputFileName, 1, wxALIGN_CENTER_VERTICAL, 5 ); bSizerTop->Add( m_outputFileName, 1, wxALL|wxEXPAND, 5 );
m_browseButton = new STD_BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,-1 ), wxBU_AUTODRAW|0 ); m_browseButton = new STD_BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,-1 ), wxBU_AUTODRAW|0 );
bSizerTop->Add( m_browseButton, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 ); bSizerTop->Add( m_browseButton, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
bMainSizer->Add( bSizerTop, 0, wxBOTTOM|wxEXPAND|wxTOP, 15 ); bMainSizer->Add( bSizerTop, 0, wxALL|wxEXPAND, 5 );
wxBoxSizer* bSizer3; wxBoxSizer* bSizer3;
bSizer3 = new wxBoxSizer( wxHORIZONTAL ); bSizer3 = new wxBoxSizer( wxHORIZONTAL );
@ -44,47 +44,52 @@ DIALOG_EXPORT_ODBPP_BASE::DIALOG_EXPORT_ODBPP_BASE( wxWindow* parent, wxWindowID
wxFlexGridSizer* fgSizer; wxFlexGridSizer* fgSizer;
fgSizer = new wxFlexGridSizer( 0, 2, 0, 0 ); fgSizer = new wxFlexGridSizer( 0, 2, 0, 0 );
fgSizer->AddGrowableCol( 0 );
fgSizer->AddGrowableCol( 1 ); fgSizer->AddGrowableCol( 1 );
fgSizer->SetFlexibleDirection( wxBOTH ); fgSizer->SetFlexibleDirection( wxBOTH );
fgSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); fgSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_lblUnits = new wxStaticText( sbSizer1->GetStaticBox(), wxID_ANY, _("Units:"), wxDefaultPosition, wxDefaultSize, 0 ); m_lblUnits = new wxStaticText( sbSizer1->GetStaticBox(), wxID_ANY, _("Units:"), wxDefaultPosition, wxDefaultSize, 0 );
m_lblUnits->Wrap( -1 ); m_lblUnits->Wrap( -1 );
fgSizer->Add( m_lblUnits, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); fgSizer->Add( m_lblUnits, 0, wxALIGN_CENTER_VERTICAL, 5 );
wxString m_choiceUnitsChoices[] = { _("Millimeters"), _("Inches") }; wxString m_choiceUnitsChoices[] = { _("Millimeters"), _("Inches") };
int m_choiceUnitsNChoices = sizeof( m_choiceUnitsChoices ) / sizeof( wxString ); int m_choiceUnitsNChoices = sizeof( m_choiceUnitsChoices ) / sizeof( wxString );
m_choiceUnits = new wxChoice( sbSizer1->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxSize( 130,30 ), m_choiceUnitsNChoices, m_choiceUnitsChoices, 0 ); m_choiceUnits = new wxChoice( sbSizer1->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxSize( -1,-1 ), m_choiceUnitsNChoices, m_choiceUnitsChoices, 0 );
m_choiceUnits->SetSelection( 0 ); m_choiceUnits->SetSelection( 0 );
fgSizer->Add( m_choiceUnits, 0, wxALIGN_RIGHT|wxALL, 5 ); fgSizer->Add( m_choiceUnits, 0, wxEXPAND|wxALL, 5 );
m_lblPrecision = new wxStaticText( sbSizer1->GetStaticBox(), wxID_ANY, _("Precision:"), wxDefaultPosition, wxDefaultSize, 0 ); m_lblPrecision = new wxStaticText( sbSizer1->GetStaticBox(), wxID_ANY, _("Precision:"), wxDefaultPosition, wxDefaultSize, 0 );
m_lblPrecision->Wrap( -1 ); m_lblPrecision->Wrap( -1 );
m_lblPrecision->SetToolTip( _("The number of values following the decimal separator") ); m_lblPrecision->SetToolTip( _("The number of values following the decimal separator") );
fgSizer->Add( m_lblPrecision, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); fgSizer->Add( m_lblPrecision, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_precision = new wxSpinCtrl( sbSizer1->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 130,30 ), wxSP_ARROW_KEYS, 2, 16, 7 ); m_precision = new wxSpinCtrl( sbSizer1->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1,-1 ), wxSP_ARROW_KEYS, 2, 16, 6 );
m_precision->SetToolTip( _("The number of values following the decimal separator") ); m_precision->SetToolTip( _("The number of values following the decimal separator") );
fgSizer->Add( m_precision, 0, wxALIGN_RIGHT|wxALL, 5 ); fgSizer->Add( m_precision, 0, wxALL|wxEXPAND, 5 );
m_cbCompress = new wxCheckBox( sbSizer1->GetStaticBox(), wxID_ANY, _("Compress output"), wxDefaultPosition, wxDefaultSize, 0 ); m_lblCompress = new wxStaticText( sbSizer1->GetStaticBox(), wxID_ANY, _("Compression Format:"), wxDefaultPosition, wxDefaultSize, 0 );
m_cbCompress->SetToolTip( _("Compress output into 'zip' file") ); m_lblCompress->Wrap( -1 );
m_lblCompress->SetToolTip( _("Select the format to compress the output ODB++ files") );
fgSizer->Add( m_cbCompress, 0, wxALIGN_CENTER_VERTICAL|wxALL|wxEXPAND, 5 ); fgSizer->Add( m_lblCompress, 0, wxALIGN_CENTER_VERTICAL, 5 );
wxString m_choiceCompressChoices[] = { _("None"), _("ZIP"), _("TGZ") };
int m_choiceCompressNChoices = sizeof( m_choiceCompressChoices ) / sizeof( wxString );
m_choiceCompress = new wxChoice( sbSizer1->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxSize( -1,-1 ), m_choiceCompressNChoices, m_choiceCompressChoices, 0 );
m_choiceCompress->SetSelection( 1 );
fgSizer->Add( m_choiceCompress, 0, wxALL|wxEXPAND, 5 );
sbSizer1->Add( fgSizer, 3, wxEXPAND|wxALL, 5 ); sbSizer1->Add( fgSizer, 3, wxEXPAND|wxLEFT, 5 );
bSizer3->Add( sbSizer1, 1, wxEXPAND|wxLEFT|wxRIGHT|wxTOP, 10 ); bSizer3->Add( sbSizer1, 1, wxEXPAND|wxALL, 10 );
bMainSizer->Add( bSizer3, 0, wxEXPAND, 5 ); bMainSizer->Add( bSizer3, 0, wxEXPAND, 10 );
bMainSizer->Add( 0, 0, 1, wxEXPAND, 5 );
m_stdButtons = new wxStdDialogButtonSizer(); m_stdButtons = new wxStdDialogButtonSizer();
m_stdButtonsOK = new wxButton( this, wxID_OK ); m_stdButtonsOK = new wxButton( this, wxID_OK );
@ -98,12 +103,13 @@ DIALOG_EXPORT_ODBPP_BASE::DIALOG_EXPORT_ODBPP_BASE( wxWindow* parent, wxWindowID
this->SetSizer( bMainSizer ); this->SetSizer( bMainSizer );
this->Layout(); this->Layout();
bMainSizer->Fit( this );
this->Centre( wxBOTH ); this->Centre( wxBOTH );
// Connect Events // Connect Events
m_browseButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EXPORT_ODBPP_BASE::onBrowseClicked ), NULL, this ); m_browseButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EXPORT_ODBPP_BASE::onBrowseClicked ), NULL, this );
m_cbCompress->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_EXPORT_ODBPP_BASE::onCompressCheck ), NULL, this ); m_choiceCompress->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_EXPORT_ODBPP_BASE::onFormatChoice ), NULL, this );
m_stdButtonsOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EXPORT_ODBPP_BASE::onOKClick ), NULL, this ); m_stdButtonsOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EXPORT_ODBPP_BASE::onOKClick ), NULL, this );
} }
@ -111,7 +117,7 @@ DIALOG_EXPORT_ODBPP_BASE::~DIALOG_EXPORT_ODBPP_BASE()
{ {
// Disconnect Events // Disconnect Events
m_browseButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EXPORT_ODBPP_BASE::onBrowseClicked ), NULL, this ); m_browseButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EXPORT_ODBPP_BASE::onBrowseClicked ), NULL, this );
m_cbCompress->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_EXPORT_ODBPP_BASE::onCompressCheck ), NULL, this ); m_choiceCompress->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_EXPORT_ODBPP_BASE::onFormatChoice ), NULL, this );
m_stdButtonsOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EXPORT_ODBPP_BASE::onOKClick ), NULL, this ); m_stdButtonsOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EXPORT_ODBPP_BASE::onOKClick ), NULL, this );
} }

View File

@ -28,7 +28,6 @@ class STD_BITMAP_BUTTON;
#include <wx/sizer.h> #include <wx/sizer.h>
#include <wx/choice.h> #include <wx/choice.h>
#include <wx/spinctrl.h> #include <wx/spinctrl.h>
#include <wx/checkbox.h>
#include <wx/statbox.h> #include <wx/statbox.h>
#include <wx/dialog.h> #include <wx/dialog.h>
@ -50,20 +49,21 @@ class DIALOG_EXPORT_ODBPP_BASE : public DIALOG_SHIM
wxChoice* m_choiceUnits; wxChoice* m_choiceUnits;
wxStaticText* m_lblPrecision; wxStaticText* m_lblPrecision;
wxSpinCtrl* m_precision; wxSpinCtrl* m_precision;
wxCheckBox* m_cbCompress; wxStaticText* m_lblCompress;
wxChoice* m_choiceCompress;
wxStdDialogButtonSizer* m_stdButtons; wxStdDialogButtonSizer* m_stdButtons;
wxButton* m_stdButtonsOK; wxButton* m_stdButtonsOK;
wxButton* m_stdButtonsCancel; wxButton* m_stdButtonsCancel;
// Virtual event handlers, override them in your derived class // Virtual event handlers, override them in your derived class
virtual void onBrowseClicked( wxCommandEvent& event ) { event.Skip(); } virtual void onBrowseClicked( wxCommandEvent& event ) { event.Skip(); }
virtual void onCompressCheck( wxCommandEvent& event ) { event.Skip(); } virtual void onFormatChoice( wxCommandEvent& event ) { event.Skip(); }
virtual void onOKClick( wxCommandEvent& event ) { event.Skip(); } virtual void onOKClick( wxCommandEvent& event ) { event.Skip(); }
public: public:
DIALOG_EXPORT_ODBPP_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Export ODB++"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 380,300 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); DIALOG_EXPORT_ODBPP_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Export ODB++"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxBORDER_DEFAULT );
~DIALOG_EXPORT_ODBPP_BASE(); ~DIALOG_EXPORT_ODBPP_BASE();

View File

@ -1420,8 +1420,8 @@ void PCB_EDIT_FRAME::GenODBPPFiles( wxCommandEvent& event )
job.SetOutputPath( dlg.GetOutputPath() ); job.SetOutputPath( dlg.GetOutputPath() );
job.m_filename = GetBoard()->GetFileName(); job.m_filename = GetBoard()->GetFileName();
job.m_compressionMode = dlg.GetCompress() ? JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::ZIP job.m_compressionMode = static_cast<JOB_EXPORT_PCB_ODB::ODB_COMPRESSION>( dlg.GetCompressFormat() );
: JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::NONE;
job.m_precision = dlg.GetPrecision(); job.m_precision = dlg.GetPrecision();
job.m_units = dlg.GetUnitsString() == "mm" ? JOB_EXPORT_PCB_ODB::ODB_UNITS::MILLIMETERS job.m_units = dlg.GetUnitsString() == "mm" ? JOB_EXPORT_PCB_ODB::ODB_UNITS::MILLIMETERS
: JOB_EXPORT_PCB_ODB::ODB_UNITS::INCHES; : JOB_EXPORT_PCB_ODB::ODB_UNITS::INCHES;

View File

@ -90,7 +90,7 @@ bool PCB_IO_ODBPP::ExportODB( const wxString& aFileName )
try try
{ {
std::shared_ptr<ODB_TREE_WRITER> writer = std::shared_ptr<ODB_TREE_WRITER> writer =
std::make_shared<ODB_TREE_WRITER>( aFileName, "odb" ); std::make_shared<ODB_TREE_WRITER>( aFileName );
writer->SetRootPath( writer->GetCurrentPath() ); writer->SetRootPath( writer->GetCurrentPath() );
if( m_progressReporter ) if( m_progressReporter )

View File

@ -1842,15 +1842,39 @@ int PCBNEW_JOBS_HANDLER::JobExportOdb( JOB* aJob )
if( !brd ) if( !brd )
return CLI::EXIT_CODES::ERR_INVALID_INPUT_FILE; return CLI::EXIT_CODES::ERR_INVALID_INPUT_FILE;
if( job->OutputPathFullSpecified() ) wxFileName fn( brd->GetFileName() );
{ wxString path = job->GetOutputPath();
wxFileName fn = brd->GetFileName();
fn.SetName( fn.GetName() );
fn.SetExt( "zip" );
job->SetOutputPath( fn.GetName() ); if( path.IsEmpty() )
{
wxFileName outputfn( fn.GetPath(), wxString::Format( wxS( "%s-odb" ), fn.GetName() ) );
path = outputfn.GetFullPath();
} }
wxFileName fileName( path );
int sepIdx = std::max( path.Find( '/', true ), path.Find( '\\', true ) );
int dotIdx = path.Find( '.', true );
if( fileName.IsDir() && path.EndsWith( wxFileName::GetPathSeparator() ) )
path = path.Mid( 0, sepIdx );
else if( sepIdx < dotIdx )
path = path.Mid( 0, dotIdx );
switch( job->m_compressionMode )
{
case JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::ZIP:
path = path + '.' + FILEEXT::ArchiveFileExtension;
break;
case JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::TGZ: path += ".tgz"; break;
case JOB_EXPORT_PCB_ODB::ODB_COMPRESSION::NONE:
path = wxFileName( path, "" ).GetFullPath();
break;
default: break;
};
job->SetOutputPath( path );
DIALOG_EXPORT_ODBPP::GenerateODBPPFiles( *job, brd, nullptr, m_progressReporter, m_reporter ); DIALOG_EXPORT_ODBPP::GenerateODBPPFiles( *job, brd, nullptr, m_progressReporter, m_reporter );
return CLI::EXIT_CODES::SUCCESS; return CLI::EXIT_CODES::SUCCESS;

View File

@ -206,7 +206,7 @@ public:
{ {
int precision; int precision;
int units; int units;
bool compress; int compressFormat;
}; };
struct DIALOG_EXPORT_SVG struct DIALOG_EXPORT_SVG