KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_export_2581.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
21
22#include <set>
23#include <map>
24#include <vector>
25
26#include <wx/filedlg.h>
27#include <wx/filefn.h>
28#include <kiplatform/ui.h>
29
30#include <board.h>
31#include <footprint.h>
32#include <kiway_holder.h>
33#include <pcb_edit_frame.h>
34#include <pcbnew_settings.h>
35#include <pgm_base.h>
36#include <project.h>
38#include <pcb_io/pcb_io_mgr.h>
42#include <string_utils.h>
45#include <wx_filename.h>
46
47
48
50 DIALOG_EXPORT_2581_BASE( aParent ),
51 m_parent( aParent ),
52 m_job( nullptr )
53{
55
56 SetupStandardButtons( { { wxID_OK, _( "Export" ) },
57 { wxID_CANCEL, _( "Close" ) } } );
58
59 // DIALOG_SHIM needs a unique hash_key because classname will be the same for both job and
60 // non-job versions.
61 m_hash_key = TO_UTF8( GetTitle() );
62
63 init();
64
65 // Now all widgets have the size fixed, call FinishDialogSettings
67}
68
69
71 wxWindow* aParent ) :
72 DIALOG_EXPORT_2581_BASE( aParent ),
73 m_parent( aEditFrame ),
74 m_job( aJob )
75{
76 m_browseButton->Hide();
77
79
80 SetTitle( m_job->GetSettingsDialogTitle() );
81
82 // DIALOG_SHIM needs a unique hash_key because classname will be the same for both job and
83 // non-job versions.
84 m_hash_key = TO_UTF8( GetTitle() );
85
86 init();
87
88 // Now all widgets have the size fixed, call FinishDialogSettings
90}
91
92
93void DIALOG_EXPORT_2581::onBrowseClicked( wxCommandEvent& event )
94{
95 // Build the absolute path of current output directory to preselect it in the file browser.
96 wxString path = ExpandEnvVarSubstitutions( m_outputFileName->GetValue(), &Prj() );
97 wxFileName fn( Prj().AbsolutePath( path ) );
98 wxString ipc_files = _( "IPC-2581 Files (*.xml)|*.xml" );
99 wxString compressed_files = _( "IPC-2581 Compressed Files (*.zip)|*.zip" );
100
101 wxFileDialog dlg( this, _( "Export IPC-2581 File" ), fn.GetPath(), fn.GetFullName(),
102 m_cbCompress->IsChecked() ? compressed_files : ipc_files,
103 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
104
106
107 if( dlg.ShowModal() == wxID_CANCEL )
108 return;
109
110 m_outputFileName->SetValue( dlg.GetPath() );
111
112}
113
114void DIALOG_EXPORT_2581::onCompressCheck( wxCommandEvent& event )
115{
116 if( m_cbCompress->GetValue() )
117 {
118 wxFileName fn = m_outputFileName->GetValue();
119
120 fn.SetExt( "zip" );
121 m_outputFileName->SetValue( fn.GetFullPath() );
122 }
123 else
124 {
125 wxFileName fn = m_outputFileName->GetValue();
126
127 fn.SetExt( "xml" );
128 m_outputFileName->SetValue( fn.GetFullPath() );
129 }
130}
131
132
133void DIALOG_EXPORT_2581::onMfgPNChange( wxCommandEvent& event )
134{
135 if( event.GetSelection() == 0 )
136 {
137 m_choiceMfg->Enable( false );
138 }
139 else
140 {
141 m_choiceMfg->Enable( true );
142
143 // Don't try to guess the manufacturer if the user has already selected one
144 if( m_choiceMfg->GetSelection() > 0 )
145 return;
146
147 int it = 0;
148
149 if( it = m_choiceMfg->FindString( wxT( "manufacturer" ) ); it != wxNOT_FOUND )
150 m_choiceMfg->Select( it );
151 else if( it = m_choiceMfg->FindString( _( "manufacturer" ) ); it != wxNOT_FOUND )
152 m_choiceMfg->Select( it );
153 else if( it = m_choiceMfg->FindString( wxT( "mfg" ) ); it != wxNOT_FOUND )
154 m_choiceMfg->Select( it );
155 else if( it = m_choiceMfg->FindString( _( "mfg" ) ); it != wxNOT_FOUND )
156 m_choiceMfg->Select( it );
157 }
158}
159
160
161void DIALOG_EXPORT_2581::onDistPNChange( wxCommandEvent& event )
162{
163 if( event.GetSelection() == 0 )
164 {
165 m_textDistributor->Enable( false );
166 m_textDistributor->SetValue( _( "N/A" ) );
167 }
168 else
169 {
170 m_textDistributor->Enable( true );
171
172 // Don't try to guess the distributor if the user has already selected one
173 if( m_textDistributor->GetValue() != _( "N/A" ) )
174 return;
175
176 wxString dist = m_choiceDistPN->GetStringSelection();
177 dist.MakeUpper();
178
179 // Try to guess the distributor from the part number column
180
181 if( dist.Contains( wxT( "DIGIKEY" ) ) )
182 {
183 m_textDistributor->SetValue( wxT( "Digi-Key" ) );
184 }
185 else if( dist.Contains( wxT( "DIGI-KEY" ) ) )
186 {
187 m_textDistributor->SetValue( wxT( "Digi-Key" ) );
188 }
189 else if( dist.Contains( wxT( "MOUSER" ) ) )
190 {
191 m_textDistributor->SetValue( wxT( "Mouser" ) );
192 }
193 else if( dist.Contains( wxT( "NEWARK" ) ) )
194 {
195 m_textDistributor->SetValue( wxT( "Newark" ) );
196 }
197 else if( dist.Contains( wxT( "RS COMPONENTS" ) ) )
198 {
199 m_textDistributor->SetValue( wxT( "RS Components" ) );
200 }
201 else if( dist.Contains( wxT( "FARNELL" ) ) )
202 {
203 m_textDistributor->SetValue( wxT( "Farnell" ) );
204 }
205 else if( dist.Contains( wxT( "ARROW" ) ) )
206 {
207 m_textDistributor->SetValue( wxT( "Arrow" ) );
208 }
209 else if( dist.Contains( wxT( "AVNET" ) ) )
210 {
211 m_textDistributor->SetValue( wxT( "Avnet" ) );
212 }
213 else if( dist.Contains( wxT( "TME" ) ) )
214 {
215 m_textDistributor->SetValue( wxT( "TME" ) );
216 }
217 else if( dist.Contains( wxT( "LCSC" ) ) )
218 {
219 m_textDistributor->SetValue( wxT( "LCSC" ) );
220 }
221 }
222}
223
224
225void DIALOG_EXPORT_2581::onOKClick( wxCommandEvent& event )
226{
227 if( m_job )
228 {
230 EndModal( wxID_OK );
231
232 return;
233 }
234
236 return;
237
238 m_messagesPanel->Clear();
239
240 REPORTER& reporter = m_messagesPanel->Reporter();
241
242 wxFileName pcbFileName = GetOutputPath();
244
245 if( pcbFileName.GetName().empty() )
246 {
247 reporter.Report( _( "The board must be saved before generating IPC-2581 file." ),
249 return;
250 }
251
252 if( !m_parent->IsWritable( pcbFileName ) )
253 {
254 reporter.Report( wxString::Format( _( "Insufficient permissions to write file '%s'." ),
255 pcbFileName.GetFullPath() ),
257 return;
258 }
259
260 wxString tempFile = wxFileName::CreateTempFileName( wxS( "pcbnew_ipc" ) );
261
262 WX_PROGRESS_REPORTER progress( this, _( "Generate IPC-2581 File" ), 5, PR_CAN_ABORT );
263
264 std::map<std::string, UTF8> props;
265
266 props[ "units" ] = TO_UTF8( GetUnitsString() );
267 props[ "sigfig" ] = TO_UTF8( GetPrecision() );
268 props[ "version" ] = TO_UTF8( wxString( GetVersion() ) );
269 props[ "OEMRef" ] = TO_UTF8( GetOEM() );
270 props[ "mpn" ] = TO_UTF8( GetMPN() );
271 props[ "mfg" ] = TO_UTF8( GetMfg() );
272 props[ "dist" ] = TO_UTF8( GetDist() );
273 props[ "distpn" ] = TO_UTF8( GetDistPN() );
274
275 wxString bomRev = m_textBomRev->GetValue();
276
277 if( !bomRev.IsEmpty() )
278 props[ "bomrev" ] = TO_UTF8( bomRev );
279
280 try
281 {
283 pi->SetProgressReporter( &progress );
284 pi->SetReporter( &reporter );
285 pi->SaveBoard( tempFile, m_parent->GetBoard(), &props );
286 }
287 catch( const IO_ERROR& ioe )
288 {
289 reporter.Report( wxString::Format( _( "Error generating IPC-2581 file '%s'.\n%s" ),
290 pcbFileName.GetFullPath(), ioe.What() ),
292
293 wxRemoveFile( tempFile );
294 return;
295 }
296
297 if( wxFileExists( pcbFileName.GetFullPath() ) )
298 wxRemoveFile( pcbFileName.GetFullPath() );
299
300 if( !wxRenameFile( tempFile, pcbFileName.GetFullPath() ) )
301 {
302 reporter.Report( wxString::Format( _( "Failed to create file '%s'." ), pcbFileName.GetFullPath() ),
304 wxRemoveFile( tempFile );
305 return;
306 }
307
308 reporter.Report( _( "IPC-2581 file generated successfully." ), RPT_SEVERITY_ACTION );
309}
310
311
313{
314 m_textDistributor->SetSize( m_choiceDistPN->GetSize() );
315
316 std::set<wxString> options;
317
318 for( FOOTPRINT* fp : m_parent->GetBoard()->Footprints() )
319 {
320 for( PCB_FIELD* field : fp->GetFields() )
321 {
322 wxCHECK2( field, continue );
323
324 options.insert( field->GetName() );
325 }
326 }
327
328 std::vector<wxString> items( options.begin(), options.end() );
329 m_oemRef->Append( items );
330 m_choiceMPN->Append( items );
331 m_choiceMfg->Append( items );
332 m_choiceDistPN->Append( items );
333}
334
335
337{
338 if( !m_job )
339 {
340 wxString path = m_outputFileName->GetValue();
341
342 if( path.IsEmpty() )
343 {
344 wxFileName brdFile( m_parent->GetBoard()->GetFileName() );
345 brdFile.SetExt( wxT( "xml" ) );
346 path = brdFile.GetFullPath();
347 m_outputFileName->SetValue( path );
348 }
349 }
350 else
351 {
352 m_choiceUnits->SetSelection( m_job->m_units == JOB_EXPORT_PCB_IPC2581::IPC2581_UNITS::MM ? 0 : 1 );
353 m_precision->SetValue( static_cast<int>( m_job->m_precision ) );
354 m_versionChoice->SetSelection( m_job->m_version == JOB_EXPORT_PCB_IPC2581::IPC2581_VERSION::B ? 0 : 1 );
355 m_cbCompress->SetValue( m_job->m_compress );
356 m_outputFileName->SetValue( m_job->GetConfiguredOutputPath() );
357 }
358
359 wxCommandEvent dummy;
361
363
364 wxString internalIdCol;
365 wxString mpnCol;
366 wxString distPnCol;
367 wxString mfgCol;
368 wxString distCol;
369
370 if( !m_job )
371 {
372 internalIdCol = prj.m_IP2581Bom.id;
373 mpnCol = prj.m_IP2581Bom.MPN;
374 distPnCol = prj.m_IP2581Bom.distPN;
375 mfgCol = prj.m_IP2581Bom.mfg;
376 distCol = prj.m_IP2581Bom.dist;
377 wxString bomRev = prj.m_IP2581Bom.bomRev;
378
379 if( bomRev.IsEmpty() )
380 bomRev = prj.m_IP2581Bom.schRevision;
381
382 m_textBomRev->SetValue( bomRev );
383 }
384 else
385 {
386 internalIdCol = m_job->m_colInternalId;
387 mpnCol = m_job->m_colMfgPn;
388 distPnCol = m_job->m_colDistPn;
389 mfgCol = m_job->m_colMfg;
390 distCol = m_job->m_colDist;
391 m_textBomRev->SetValue( m_job->m_bomRev );
392 }
393
394 if( !m_choiceMPN->SetStringSelection( internalIdCol ) )
395 m_choiceMPN->SetSelection( 0 );
396
397 if( m_choiceMPN->SetStringSelection( mpnCol ) )
398 {
399 m_choiceMfg->Enable( true );
400
401 if( !m_choiceMfg->SetStringSelection( mfgCol ) )
402 m_choiceMfg->SetSelection( 0 );
403 }
404 else
405 {
406 m_choiceMPN->SetSelection( 0 );
407 m_choiceMfg->SetSelection( 0 );
408 m_choiceMfg->Enable( false );
409 }
410
411 if( m_choiceDistPN->SetStringSelection( distPnCol ) )
412 {
413 m_textDistributor->Enable( true );
414
415 // The combo box selection can be fixed, so any value can be entered
416 if( !prj.m_IP2581Bom.distPN.empty() )
417 {
418 m_textDistributor->SetValue( distCol );
419 }
420 else
421 {
422 wxCommandEvent evt;
423 onDistPNChange( evt );
424 }
425 }
426 else
427 {
428 m_choiceDistPN->SetSelection( 0 );
429 m_textDistributor->SetValue( _( "N/A" ) );
430 m_textDistributor->Enable( false );
431 }
432
433 return true;
434}
435
436
438{
439 if( !m_job )
440 {
442
443 prj.m_IP2581Bom.id = GetOEM();
444 prj.m_IP2581Bom.mfg = GetMfg();
445 prj.m_IP2581Bom.MPN = GetMPN();
447 prj.m_IP2581Bom.dist = GetDist();
448 prj.m_IP2581Bom.bomRev = m_textBomRev->GetValue();
449 }
450 else
451 {
452 m_job->SetConfiguredOutputPath( m_outputFileName->GetValue() );
453
454 m_job->m_colInternalId = GetOEM();
455 m_job->m_colDist = GetDist();
456 m_job->m_colDistPn = GetDistPN();
457 m_job->m_colMfg = GetMfg();
458 m_job->m_colMfgPn = GetMPN();
459 m_job->m_bomRev = m_textBomRev->GetValue();
460
465 m_job->m_precision = m_precision->GetValue();
466 m_job->m_compress = GetCompress();
467 }
468
469 return true;
470}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
DIALOG_EXPORT_2581_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Export IPC-2581"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
WX_HTML_REPORT_PANEL * m_messagesPanel
STD_BITMAP_BUTTON * m_browseButton
void onMfgPNChange(wxCommandEvent &event) override
wxString GetOEM() const
wxString GetPrecision() const
bool TransferDataToWindow() override
void onCompressCheck(wxCommandEvent &event) override
void onOKClick(wxCommandEvent &event) override
wxString GetMPN() const
void onDistPNChange(wxCommandEvent &event) override
bool TransferDataFromWindow() override
wxString GetDistPN() const
DIALOG_EXPORT_2581(PCB_EDIT_FRAME *aParent)
PCB_EDIT_FRAME * m_parent
wxString GetDist() const
wxString GetMfg() const
void onBrowseClicked(wxCommandEvent &event) override
wxString GetUnitsString() const
JOB_EXPORT_PCB_IPC2581 * m_job
wxString GetOutputPath() const
void SetupStandardButtons(std::map< int, wxString > aLabels={})
std::string m_hash_key
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
The main frame for Pcbnew.
static PCB_IO * FindPlugin(PCB_FILE_T aFileType)
Return a #PLUGIN which the caller can use to import, export, save, or load design documents.
The backing store for a PROJECT, in JSON format.
struct IP2581_BOM m_IP2581Bom
Layer pair list for the board.
virtual PROJECT_FILE & GetProjectFile() const
Definition project.h:203
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:73
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition reporter.h:102
static void ResolvePossibleSymlinks(wxFileName &aFilename)
Multi-thread safe progress reporter dialog, intended for use of tasks that parallel reporting back of...
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
Definition common.cpp:558
#define _(s)
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition io_mgr.h:33
void AllowNetworkFileSystems(wxDialog *aDialog)
Configure a file dialog to show network and virtual file systems.
Definition wxgtk/ui.cpp:435
see class PGM_BASE
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_ACTION
std::vector< FAB_LAYER_COLOR > dummy
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
wxString mfg
Manufacturer name column.
wxString bomRev
Explicit BOM revision override set by user.
wxString schRevision
Auto-propagated schematic title block revision.
wxString MPN
Manufacturer part number column.
wxString id
Internal ID column.
wxString dist
Distributor name column.
wxString distPN
Distributor part number column.
std::string path
#define PR_CAN_ABORT