diff --git a/common/jobs/job.h b/common/jobs/job.h index a6313cea10..e9061e2b2d 100644 --- a/common/jobs/job.h +++ b/common/jobs/job.h @@ -63,6 +63,52 @@ protected: ValueType m_default; }; + +template +class JOB_PARAM_LIST : public JOB_PARAM_BASE +{ +public: + JOB_PARAM_LIST( const std::string& aJsonPath, std::vector* aPtr, + std::vector aDefault ) : + JOB_PARAM_BASE( aJsonPath ), + m_ptr( aPtr ), + m_default( std::move( aDefault ) ) + { } + + virtual void FromJson( const nlohmann::json& j ) const override + { + if( j.contains( m_jsonPath ) ) + { + auto js = j.at( m_jsonPath ); + std::vector val; + + if( js.is_array() ) + { + for( const auto& el : js.items() ) + val.push_back( el.value().get() ); + } + + *m_ptr = val; + } + else + *m_ptr = m_default; + } + + void ToJson( nlohmann::json& j ) override + { + nlohmann::json js = nlohmann::json::array(); + + for( const auto& el : *m_ptr ) + js.push_back( el ); + + j[m_jsonPath] = js; + } + +protected: + std::vector* m_ptr; + std::vector m_default; +}; + struct KICOMMON_API JOB_OUTPUT { JOB_OUTPUT(){}; diff --git a/common/jobs/job_export_sch_bom.cpp b/common/jobs/job_export_sch_bom.cpp index 9c83a29da6..5420fe6055 100644 --- a/common/jobs/job_export_sch_bom.cpp +++ b/common/jobs/job_export_sch_bom.cpp @@ -59,13 +59,13 @@ JOB_EXPORT_SCH_BOM::JOB_EXPORT_SCH_BOM() : m_params.emplace_back( new JOB_PARAM( "keep_line_breaks", &m_keepLineBreaks, m_keepLineBreaks ) ); - m_params.emplace_back( new JOB_PARAM>( "fields_ordered", + m_params.emplace_back( new JOB_PARAM_LIST( "fields_ordered", &m_fieldsOrdered, m_fieldsOrdered ) ); - m_params.emplace_back( new JOB_PARAM>( "fields_labels", + m_params.emplace_back( new JOB_PARAM_LIST( "fields_labels", &m_fieldsLabels, m_fieldsLabels ) ); - m_params.emplace_back( new JOB_PARAM>( "fields_group_by", + m_params.emplace_back( new JOB_PARAM_LIST( "fields_group_by", &m_fieldsGroupBy, m_fieldsGroupBy ) ); m_params.emplace_back( new JOB_PARAM( "sort_field", &m_sortField, m_sortField ) ); diff --git a/eeschema/dialogs/dialog_symbol_fields_table.cpp b/eeschema/dialogs/dialog_symbol_fields_table.cpp index 7cd3fe6824..024f2e106d 100644 --- a/eeschema/dialogs/dialog_symbol_fields_table.cpp +++ b/eeschema/dialogs/dialog_symbol_fields_table.cpp @@ -56,6 +56,7 @@ #include #include #include +#include wxDEFINE_EVENT( EDA_EVT_CLOSE_DIALOG_SYMBOL_FIELDS_TABLE, wxCommandEvent ); @@ -168,12 +169,14 @@ protected: }; -DIALOG_SYMBOL_FIELDS_TABLE::DIALOG_SYMBOL_FIELDS_TABLE( SCH_EDIT_FRAME* parent ) : +DIALOG_SYMBOL_FIELDS_TABLE::DIALOG_SYMBOL_FIELDS_TABLE( SCH_EDIT_FRAME* parent, + JOB_EXPORT_SCH_BOM* aJob ) : DIALOG_SYMBOL_FIELDS_TABLE_BASE( parent ), m_currentBomPreset( nullptr ), m_lastSelectedBomPreset( nullptr ), m_parent( parent ), - m_schSettings( parent->Schematic().Settings() ) + m_schSettings( parent->Schematic().Settings() ), + m_job( aJob ) { // Get all symbols from the list of schematic sheets m_parent->Schematic().Hierarchy().GetSymbols( m_symbolsList, false ); @@ -267,12 +270,58 @@ DIALOG_SYMBOL_FIELDS_TABLE::DIALOG_SYMBOL_FIELDS_TABLE( SCH_EDIT_FRAME* parent ) // Load our BOM view presets SetUserBomPresets( m_schSettings.m_BomPresets ); - ApplyBomPreset( m_schSettings.m_BomSettings ); + + BOM_PRESET preset = m_schSettings.m_BomSettings; + if( m_job ) + { + preset.name = m_job->m_bomPresetName; + preset.excludeDNP = m_job->m_excludeDNP; + preset.includeExcludedFromBOM = m_job->m_includeExcludedFromBOM; + preset.filterString = m_job->m_filterString; + preset.sortAsc = m_job->m_sortAsc; + preset.sortField = m_job->m_sortField; + preset.groupSymbols = ( m_job->m_fieldsGroupBy.size() > 0 ); + + preset.fieldsOrdered.clear(); + + size_t i = 0; + for( wxString fieldName : m_job->m_fieldsOrdered ) + { + BOM_FIELD field; + field.name = fieldName; + field.show = true; + field.groupBy = std::find( m_job->m_fieldsGroupBy.begin(), m_job->m_fieldsGroupBy.end(), + field.name ) + != m_job->m_fieldsGroupBy.end(); + + if( ( m_job->m_fieldsLabels.size() > i ) && !m_job->m_fieldsLabels[i].IsEmpty() ) + field.label = m_job->m_fieldsLabels[i]; + else if( IsTextVar( field.name ) ) + field.label = GetTextVars( field.name ); + else + field.label = field.name; + + preset.fieldsOrdered.emplace_back( field ); + i++; + } + } + ApplyBomPreset( preset ); syncBomPresetSelection(); // Load BOM export format presets SetUserBomFmtPresets( m_schSettings.m_BomFmtPresets ); - ApplyBomFmtPreset( m_schSettings.m_BomFmtSettings ); + BOM_FMT_PRESET fmtPreset = m_schSettings.m_BomFmtSettings; + if( m_job ) + { + fmtPreset.name = m_job->m_bomFmtPresetName; + fmtPreset.fieldDelimiter = m_job->m_fieldDelimiter; + fmtPreset.keepLineBreaks = m_job->m_keepLineBreaks; + fmtPreset.keepTabs = m_job->m_keepTabs; + fmtPreset.refDelimiter = m_job->m_refDelimiter; + fmtPreset.refRangeDelimiter = m_job->m_refRangeDelimiter; + fmtPreset.stringDelimiter = m_job->m_stringDelimiter; + } + ApplyBomFmtPreset( fmtPreset ); syncBomFmtPresetSelection(); SetInitialFocus( m_grid ); @@ -305,7 +354,14 @@ DIALOG_SYMBOL_FIELDS_TABLE::DIALOG_SYMBOL_FIELDS_TABLE( SCH_EDIT_FRAME* parent ) case SCOPE::SCOPE_SHEET_RECURSIVE: m_radioRecursive->SetValue( true ); break; } - m_outputFileName->SetValue( m_schSettings.m_BomExportFileName ); + if( m_job ) + { + m_outputFileName->SetValue( m_job->GetOutputPath() ); + } + else + { + m_outputFileName->SetValue( m_schSettings.m_BomExportFileName ); + } Center(); @@ -319,8 +375,23 @@ DIALOG_SYMBOL_FIELDS_TABLE::DIALOG_SYMBOL_FIELDS_TABLE( SCH_EDIT_FRAME* parent ) m_fieldsCtrl->Bind( wxEVT_DATAVIEW_ITEM_VALUE_CHANGED, &DIALOG_SYMBOL_FIELDS_TABLE::OnColLabelChange, this ); - // Start listening for schematic changes - m_parent->Schematic().AddListener( this ); + if( !m_job ) + { + // Start listening for schematic changes + m_parent->Schematic().AddListener( this ); + } + else + { + // Don't allow editing + m_grid->EnableEditing( false ); + m_buttonApply->Hide(); + m_buttonExport->Hide(); + + SetupStandardButtons( { { wxID_OK, _( "Save" ) }, + { wxID_CANCEL, _( "Close" ) } } ); + + SetTitle( _( "BOM Export Job" ) ); + } } @@ -536,6 +607,12 @@ bool DIALOG_SYMBOL_FIELDS_TABLE::TransferDataFromWindow() if( !wxDialog::TransferDataFromWindow() ) return false; + if( m_job ) + { + // and exit, dont even dream of saving changes from the data model + return true; + } + SCH_COMMIT commit( m_parent ); SCH_SHEET_PATH currentSheet = m_parent->GetCurrentSheet(); @@ -1320,19 +1397,91 @@ void DIALOG_SYMBOL_FIELDS_TABLE::OnExport( wxCommandEvent& aEvent ) void DIALOG_SYMBOL_FIELDS_TABLE::OnCancel( wxCommandEvent& aEvent ) { - Close(); + if( m_job ) + { + EndModal( wxID_CANCEL ); + } + else + { + Close(); + } } void DIALOG_SYMBOL_FIELDS_TABLE::OnOk( wxCommandEvent& aEvent ) { TransferDataFromWindow(); - Close(); + if( m_job ) + { + m_job->SetOutputPath( m_outputFileName->GetValue() ); + + if( m_currentBomFmtPreset ) + { + m_job->m_bomFmtPresetName = m_currentBomFmtPreset->name; + } + else + { + m_job->m_bomFmtPresetName = wxEmptyString; + } + + if( m_currentBomPreset ) + { + m_job->m_bomPresetName = m_currentBomPreset->name; + } + else + { + m_job->m_bomPresetName = wxEmptyString; + } + + BOM_FMT_PRESET fmtSettings = GetCurrentBomFmtSettings(); + m_job->m_fieldDelimiter = fmtSettings.fieldDelimiter; + m_job->m_stringDelimiter = fmtSettings.stringDelimiter; + m_job->m_refDelimiter = fmtSettings.refDelimiter; + m_job->m_refRangeDelimiter = fmtSettings.refRangeDelimiter; + m_job->m_keepTabs = fmtSettings.keepTabs; + m_job->m_keepLineBreaks = fmtSettings.keepLineBreaks; + + BOM_PRESET presetFields = m_dataModel->GetBomSettings(); + m_job->m_sortAsc = presetFields.sortAsc; + m_job->m_excludeDNP = presetFields.excludeDNP; + m_job->m_includeExcludedFromBOM = presetFields.includeExcludedFromBOM; + m_job->m_filterString = presetFields.filterString; + m_job->m_sortField = presetFields.sortField; + + m_job->m_fieldsOrdered.clear(); + m_job->m_fieldsLabels.clear(); + m_job->m_fieldsGroupBy.clear(); + for( const BOM_FIELD& modelField : m_dataModel->GetFieldsOrdered() ) + { + if( modelField.show ) + { + m_job->m_fieldsOrdered.emplace_back( modelField.name ); + m_job->m_fieldsLabels.emplace_back( modelField.label ); + + if( modelField.groupBy ) + { + m_job->m_fieldsGroupBy.emplace_back( modelField.name ); + } + } + } + + EndModal( wxID_OK ); + } + else + { + Close(); + } } void DIALOG_SYMBOL_FIELDS_TABLE::OnClose( wxCloseEvent& aEvent ) { + if( m_job ) + { + aEvent.Skip(); + return; + } + // This is a cancel, so commit quietly as we're going to throw the results away anyway. m_grid->CommitPendingChanges( true ); diff --git a/eeschema/dialogs/dialog_symbol_fields_table.h b/eeschema/dialogs/dialog_symbol_fields_table.h index bb0f46ca71..3fc93713e5 100644 --- a/eeschema/dialogs/dialog_symbol_fields_table.h +++ b/eeschema/dialogs/dialog_symbol_fields_table.h @@ -37,12 +37,13 @@ struct BOM_PRESET; struct BOM_FMT_PRESET; class SCH_EDIT_FRAME; class FIELDS_EDITOR_GRID_DATA_MODEL; +class JOB_EXPORT_SCH_BOM; class DIALOG_SYMBOL_FIELDS_TABLE : public DIALOG_SYMBOL_FIELDS_TABLE_BASE, public SCHEMATIC_LISTENER { public: - DIALOG_SYMBOL_FIELDS_TABLE( SCH_EDIT_FRAME* parent ); + DIALOG_SYMBOL_FIELDS_TABLE( SCH_EDIT_FRAME* parent, JOB_EXPORT_SCH_BOM* aJob = nullptr ); virtual ~DIALOG_SYMBOL_FIELDS_TABLE(); bool TransferDataToWindow() override; @@ -160,6 +161,8 @@ private: FIELDS_EDITOR_GRID_DATA_MODEL* m_dataModel; SCHEMATIC_SETTINGS& m_schSettings; + + JOB_EXPORT_SCH_BOM* m_job; }; #endif /* DIALOG_SYMBOL_FIELDS_TABLE_H */ diff --git a/eeschema/eeschema_jobs_handler.cpp b/eeschema/eeschema_jobs_handler.cpp index c422da0b60..30233b7b42 100644 --- a/eeschema/eeschema_jobs_handler.cpp +++ b/eeschema/eeschema_jobs_handler.cpp @@ -70,6 +70,7 @@ #include #include #include +#include EESCHEMA_JOBS_HANDLER::EESCHEMA_JOBS_HANDLER( KIWAY* aKiway ) : @@ -78,14 +79,19 @@ EESCHEMA_JOBS_HANDLER::EESCHEMA_JOBS_HANDLER( KIWAY* aKiway ) : { Register( "bom", std::bind( &EESCHEMA_JOBS_HANDLER::JobExportBom, this, std::placeholders::_1 ), - []( JOB* job, wxWindow* aParent ) -> bool + [aKiway]( JOB* job, wxWindow* aParent ) -> bool { JOB_EXPORT_SCH_BOM* bomJob = dynamic_cast( job ); if( !bomJob ) return false; - return false; + SCH_EDIT_FRAME* editFrame = + dynamic_cast( aKiway->Player( FRAME_SCH, false ) ); + + DIALOG_SYMBOL_FIELDS_TABLE dlg( editFrame, bomJob ); + + return dlg.ShowModal() == wxID_OK; } ); Register( "pythonbom", std::bind( &EESCHEMA_JOBS_HANDLER::JobExportPythonBom, this, std::placeholders::_1 ), @@ -651,10 +657,10 @@ int EESCHEMA_JOBS_HANDLER::JobExportBom( JOB* aJob ) wxFile f; - if( !f.Open( aBomJob->GetOutputPath(), wxFile::write ) ) + if( !f.Open( aBomJob->GetFullOutputPath(), wxFile::write ) ) { m_reporter->Report( wxString::Format( _( "Unable to open destination '%s'" ), - aBomJob->GetOutputPath() ), + aBomJob->GetFullOutputPath() ), RPT_SEVERITY_ERROR ); return CLI::EXIT_CODES::ERR_INVALID_INPUT_FILE; diff --git a/kicad/dialogs/panel_jobs.cpp b/kicad/dialogs/panel_jobs.cpp index a68fc7298f..a7dfb4ad6c 100644 --- a/kicad/dialogs/panel_jobs.cpp +++ b/kicad/dialogs/panel_jobs.cpp @@ -589,8 +589,13 @@ void PANEL_JOBS::openJobOptionsForListItem( size_t aItemIndex ) { EnsurePcbSchFramesOpen(); - m_frame->Kiway().ProcessJobConfigDialog( iface, job.m_job.get(), m_frame ); - } + bool changes = m_frame->Kiway().ProcessJobConfigDialog( iface, job.m_job.get(), m_frame ); + if( changes ) + { + m_jobsFile->SetDirty(); + updateTitle(); + } + } else { // special jobs @@ -657,7 +662,7 @@ void PANEL_JOBS::onJobListMenu( wxCommandEvent& aEvent ) void PANEL_JOBS::OnSaveButtonClick( wxCommandEvent& aEvent ) { - m_jobsFile->SaveToFile(); + m_jobsFile->SaveToFile( wxEmptyString, true ); updateTitle(); }