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
29#include <board.h>
30#include <footprint.h>
31#include <kiway_holder.h>
32#include <pcb_edit_frame.h>
33#include <pcbnew_settings.h>
34#include <pgm_base.h>
35#include <project.h>
37#include <pcb_io/pcb_io_mgr.h>
41#include <string_utils.h>
44#include <wx_filename.h>
45
46
47
49 DIALOG_EXPORT_2581_BASE( aParent ),
50 m_parent( aParent ),
51 m_job( nullptr )
52{
54
55 SetupStandardButtons( { { wxID_OK, _( "Export" ) },
56 { wxID_CANCEL, _( "Close" ) } } );
57
58 // DIALOG_SHIM needs a unique hash_key because classname will be the same for both job and
59 // non-job versions.
60 m_hash_key = TO_UTF8( GetTitle() );
61
62 init();
63
64 // Now all widgets have the size fixed, call FinishDialogSettings
66}
67
68
70 wxWindow* aParent ) :
71 DIALOG_EXPORT_2581_BASE( aParent ),
72 m_parent( aEditFrame ),
73 m_job( aJob )
74{
75 m_browseButton->Hide();
76
78
79 SetTitle( m_job->GetSettingsDialogTitle() );
80
81 // DIALOG_SHIM needs a unique hash_key because classname will be the same for both job and
82 // non-job versions.
83 m_hash_key = TO_UTF8( GetTitle() );
84
85 init();
86
87 // Now all widgets have the size fixed, call FinishDialogSettings
89}
90
91
92void DIALOG_EXPORT_2581::onBrowseClicked( wxCommandEvent& event )
93{
94 // Build the absolute path of current output directory to preselect it in the file browser.
95 wxString path = ExpandEnvVarSubstitutions( m_outputFileName->GetValue(), &Prj() );
96 wxFileName fn( Prj().AbsolutePath( path ) );
97 wxString ipc_files = _( "IPC-2581 Files (*.xml)|*.xml" );
98 wxString compressed_files = _( "IPC-2581 Compressed Files (*.zip)|*.zip" );
99
100 wxFileDialog dlg( this, _( "Export IPC-2581 File" ), fn.GetPath(), fn.GetFullName(),
101 m_cbCompress->IsChecked() ? compressed_files : ipc_files,
102 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
103
104 if( dlg.ShowModal() == wxID_CANCEL )
105 return;
106
107 m_outputFileName->SetValue( dlg.GetPath() );
108
109}
110
111void DIALOG_EXPORT_2581::onCompressCheck( wxCommandEvent& event )
112{
113 if( m_cbCompress->GetValue() )
114 {
115 wxFileName fn = m_outputFileName->GetValue();
116
117 fn.SetExt( "zip" );
118 m_outputFileName->SetValue( fn.GetFullPath() );
119 }
120 else
121 {
122 wxFileName fn = m_outputFileName->GetValue();
123
124 fn.SetExt( "xml" );
125 m_outputFileName->SetValue( fn.GetFullPath() );
126 }
127}
128
129
130void DIALOG_EXPORT_2581::onMfgPNChange( wxCommandEvent& event )
131{
132 if( event.GetSelection() == 0 )
133 {
134 m_choiceMfg->Enable( false );
135 }
136 else
137 {
138 m_choiceMfg->Enable( true );
139
140 // Don't try to guess the manufacturer if the user has already selected one
141 if( m_choiceMfg->GetSelection() > 0 )
142 return;
143
144 int it = 0;
145
146 if( it = m_choiceMfg->FindString( wxT( "manufacturer" ) ); it != wxNOT_FOUND )
147 m_choiceMfg->Select( it );
148 else if( it = m_choiceMfg->FindString( _( "manufacturer" ) ); it != wxNOT_FOUND )
149 m_choiceMfg->Select( it );
150 else if( it = m_choiceMfg->FindString( wxT( "mfg" ) ); it != wxNOT_FOUND )
151 m_choiceMfg->Select( it );
152 else if( it = m_choiceMfg->FindString( _( "mfg" ) ); it != wxNOT_FOUND )
153 m_choiceMfg->Select( it );
154 }
155}
156
157
158void DIALOG_EXPORT_2581::onDistPNChange( wxCommandEvent& event )
159{
160 if( event.GetSelection() == 0 )
161 {
162 m_textDistributor->Enable( false );
163 m_textDistributor->SetValue( _( "N/A" ) );
164 }
165 else
166 {
167 m_textDistributor->Enable( true );
168
169 // Don't try to guess the distributor if the user has already selected one
170 if( m_textDistributor->GetValue() != _( "N/A" ) )
171 return;
172
173 wxString dist = m_choiceDistPN->GetStringSelection();
174 dist.MakeUpper();
175
176 // Try to guess the distributor from the part number column
177
178 if( dist.Contains( wxT( "DIGIKEY" ) ) )
179 {
180 m_textDistributor->SetValue( wxT( "Digi-Key" ) );
181 }
182 else if( dist.Contains( wxT( "DIGI-KEY" ) ) )
183 {
184 m_textDistributor->SetValue( wxT( "Digi-Key" ) );
185 }
186 else if( dist.Contains( wxT( "MOUSER" ) ) )
187 {
188 m_textDistributor->SetValue( wxT( "Mouser" ) );
189 }
190 else if( dist.Contains( wxT( "NEWARK" ) ) )
191 {
192 m_textDistributor->SetValue( wxT( "Newark" ) );
193 }
194 else if( dist.Contains( wxT( "RS COMPONENTS" ) ) )
195 {
196 m_textDistributor->SetValue( wxT( "RS Components" ) );
197 }
198 else if( dist.Contains( wxT( "FARNELL" ) ) )
199 {
200 m_textDistributor->SetValue( wxT( "Farnell" ) );
201 }
202 else if( dist.Contains( wxT( "ARROW" ) ) )
203 {
204 m_textDistributor->SetValue( wxT( "Arrow" ) );
205 }
206 else if( dist.Contains( wxT( "AVNET" ) ) )
207 {
208 m_textDistributor->SetValue( wxT( "Avnet" ) );
209 }
210 else if( dist.Contains( wxT( "TME" ) ) )
211 {
212 m_textDistributor->SetValue( wxT( "TME" ) );
213 }
214 else if( dist.Contains( wxT( "LCSC" ) ) )
215 {
216 m_textDistributor->SetValue( wxT( "LCSC" ) );
217 }
218 }
219}
220
221
222void DIALOG_EXPORT_2581::onOKClick( wxCommandEvent& event )
223{
224 if( m_job )
225 {
227 EndModal( wxID_OK );
228
229 return;
230 }
231
233 return;
234
235 m_messagesPanel->Clear();
236
237 REPORTER& reporter = m_messagesPanel->Reporter();
238
239 wxFileName pcbFileName = GetOutputPath();
241
242 if( pcbFileName.GetName().empty() )
243 {
244 reporter.Report( _( "The board must be saved before generating IPC-2581 file." ),
246 return;
247 }
248
249 if( !m_parent->IsWritable( pcbFileName ) )
250 {
251 reporter.Report( wxString::Format( _( "Insufficient permissions to write file '%s'." ),
252 pcbFileName.GetFullPath() ),
254 return;
255 }
256
257 wxString tempFile = wxFileName::CreateTempFileName( wxS( "pcbnew_ipc" ) );
258
259 WX_PROGRESS_REPORTER progress( this, _( "Generate IPC-2581 File" ), 5, PR_CAN_ABORT );
260
261 std::map<std::string, UTF8> props;
262
263 props[ "units" ] = TO_UTF8( GetUnitsString() );
264 props[ "sigfig" ] = TO_UTF8( GetPrecision() );
265 props[ "version" ] = TO_UTF8( wxString( GetVersion() ) );
266 props[ "OEMRef" ] = TO_UTF8( GetOEM() );
267 props[ "mpn" ] = TO_UTF8( GetMPN() );
268 props[ "mfg" ] = TO_UTF8( GetMfg() );
269 props[ "dist" ] = TO_UTF8( GetDist() );
270 props[ "distpn" ] = TO_UTF8( GetDistPN() );
271
272 try
273 {
275 pi->SetProgressReporter( &progress );
276 pi->SetReporter( &reporter );
277 pi->SaveBoard( tempFile, m_parent->GetBoard(), &props );
278 }
279 catch( const IO_ERROR& ioe )
280 {
281 reporter.Report( wxString::Format( _( "Error generating IPC-2581 file '%s'.\n%s" ),
282 pcbFileName.GetFullPath(), ioe.What() ),
284
285 wxRemoveFile( tempFile );
286 return;
287 }
288
289 if( wxFileExists( pcbFileName.GetFullPath() ) )
290 wxRemoveFile( pcbFileName.GetFullPath() );
291
292 if( !wxRenameFile( tempFile, pcbFileName.GetFullPath() ) )
293 {
294 reporter.Report( wxString::Format( _( "Failed to create file '%s'." ), pcbFileName.GetFullPath() ),
296 wxRemoveFile( tempFile );
297 return;
298 }
299
300 reporter.Report( _( "IPC-2581 file generated successfully." ), RPT_SEVERITY_ACTION );
301}
302
303
305{
306 m_textDistributor->SetSize( m_choiceDistPN->GetSize() );
307
308 std::set<wxString> options;
309
310 for( FOOTPRINT* fp : m_parent->GetBoard()->Footprints() )
311 {
312 for( PCB_FIELD* field : fp->GetFields() )
313 options.insert( field->GetName() );
314 }
315
316 std::vector<wxString> items( options.begin(), options.end() );
317 m_oemRef->Append( items );
318 m_choiceMPN->Append( items );
319 m_choiceMfg->Append( items );
320 m_choiceDistPN->Append( items );
321}
322
323
325{
326 if( !m_job )
327 {
328 wxString path = m_outputFileName->GetValue();
329
330 if( path.IsEmpty() )
331 {
332 wxFileName brdFile( m_parent->GetBoard()->GetFileName() );
333 brdFile.SetExt( wxT( "xml" ) );
334 path = brdFile.GetFullPath();
335 m_outputFileName->SetValue( path );
336 }
337 }
338 else
339 {
340 m_choiceUnits->SetSelection( m_job->m_units == JOB_EXPORT_PCB_IPC2581::IPC2581_UNITS::MM ? 0 : 1 );
341 m_precision->SetValue( static_cast<int>( m_job->m_precision ) );
342 m_versionChoice->SetSelection( m_job->m_version == JOB_EXPORT_PCB_IPC2581::IPC2581_VERSION::B ? 0 : 1 );
343 m_cbCompress->SetValue( m_job->m_compress );
344 m_outputFileName->SetValue( m_job->GetConfiguredOutputPath() );
345 }
346
347 wxCommandEvent dummy;
349
351
352 wxString internalIdCol;
353 wxString mpnCol;
354 wxString distPnCol;
355 wxString mfgCol;
356 wxString distCol;
357
358 if( !m_job )
359 {
360 internalIdCol = prj.m_IP2581Bom.id;
361 mpnCol = prj.m_IP2581Bom.MPN;
362 distPnCol = prj.m_IP2581Bom.distPN;
363 mfgCol = prj.m_IP2581Bom.mfg;
364 distCol = prj.m_IP2581Bom.dist;
365 }
366 else
367 {
368 internalIdCol = m_job->m_colInternalId;
369 mpnCol = m_job->m_colMfgPn;
370 distPnCol = m_job->m_colDistPn;
371 mfgCol = m_job->m_colMfg;
372 distCol = m_job->m_colDist;
373 }
374
375 if( !m_choiceMPN->SetStringSelection( internalIdCol ) )
376 m_choiceMPN->SetSelection( 0 );
377
378 if( m_choiceMPN->SetStringSelection( mpnCol ) )
379 {
380 m_choiceMfg->Enable( true );
381
382 if( !m_choiceMfg->SetStringSelection( mfgCol ) )
383 m_choiceMfg->SetSelection( 0 );
384 }
385 else
386 {
387 m_choiceMPN->SetSelection( 0 );
388 m_choiceMfg->SetSelection( 0 );
389 m_choiceMfg->Enable( false );
390 }
391
392 if( m_choiceDistPN->SetStringSelection( distPnCol ) )
393 {
394 m_textDistributor->Enable( true );
395
396 // The combo box selection can be fixed, so any value can be entered
397 if( !prj.m_IP2581Bom.distPN.empty() )
398 {
399 m_textDistributor->SetValue( distCol );
400 }
401 else
402 {
403 wxCommandEvent evt;
404 onDistPNChange( evt );
405 }
406 }
407 else
408 {
409 m_choiceDistPN->SetSelection( 0 );
410 m_textDistributor->SetValue( _( "N/A" ) );
411 m_textDistributor->Enable( false );
412 }
413
414 return true;
415}
416
417
419{
420 if( !m_job )
421 {
423
424 prj.m_IP2581Bom.id = GetOEM();
425 prj.m_IP2581Bom.mfg = GetMfg();
426 prj.m_IP2581Bom.MPN = GetMPN();
428 prj.m_IP2581Bom.dist = GetDist();
429 }
430 else
431 {
432 m_job->SetConfiguredOutputPath( m_outputFileName->GetValue() );
433
434 m_job->m_colInternalId = GetOEM();
435 m_job->m_colDist = GetDist();
436 m_job->m_colDistPn = GetDistPN();
437 m_job->m_colMfg = GetMfg();
438 m_job->m_colMfgPn = GetMPN();
439
444 m_job->m_precision = m_precision->GetValue();
445 m_job->m_compress = GetCompress();
446 }
447
448 return true;
449}
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 * PluginFind(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:204
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:355
#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
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 MPN
Manufacturer part number column.
wxString id
Internal ID column.
wxString dist
Distributor name column.
wxString distPN
Distributor part number column.
#define PR_CAN_ABORT